一、背景
在SpringBoot开发应用的时候,程序抛出的异常如果能进行统一的管理和处理,会极大方便我们排查问题,SpringBoot预留了controller响应的扩展点,我们只需要按照对应的方式去自定义自己的实现即可。
@ControllerAdvice表明GlobalExceptionAdvice是一个异常的处理类; @ExceptionHandler表明当前方法即为将要处理错误信息的逻辑代码,通过value来指定异常类型。异常的处理方法需要传入两个参数,一个是HttpServletRequest请求对象,可以从这里获取请求相关的一些信息,比如请求的url或者参数等,另一个是对应自定义的Exception,它就是抛出的异常
二、集成
1.编写异常枚举类
public enum IExceptionEnum {
CURRENT_NO_PERMISSION(4001,"当前用户权限不足"),
INTERNAL_ADDRESS_FORBIDDEN_ACCESS(4003,"内部访问地址,禁止访问"),
REQUEST_PARAM_ERROR(4000,"请求参数错误"),
REQUEST_URL_ERROR(4004,"请求URL地址错误"),
REQUEST_METHOD_ERROR(4005,"请求方法错误"),
SERVER_INTERNAL_EXEC_ERROR(5000,"服务器内部执行错误"),
DB_SERVICE_ERROR(5001,"数据库服务错误"),
INTERNAL_INTERFACE_CALL_ERROR(5002,"内部接口调用错误"),
EXTERNAL_INTERFACE_CALL_ERROR(5003,"外部接口调用错误");
private Integer code;
private String message;
IExceptionEnum(Integer code, String msg) {
this.code = code;
this.message = msg;
}
public static IExceptionEnum getException(Integer code){
for (IExceptionEnum value : values()) {
if (value.getCode() == code){
return value;
}
}
return null;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return message;
}
public void setMsg(String msg) {
this.message = msg;
}
}
2.编写响应类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MyResponse implements Serializable {
private Integer code;
private String msg;
private Object data;
public static Map pageFormat2Map(Page page){
HashMap
3.编写异常处理类
@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice {
//HttpServletRequest请求对象,可以从这里获取请求相关的一些信息,比如请求的url或者参数等
@ExceptionHandler(HttpException.class)
public MyResponse httpException(HttpServletRequest request, HttpException e){
log.error(getExceptionDetail(e));
return MyResponse.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(RuntimeException.class)
public MyResponse runtimeException(HttpServletRequest request, RuntimeException e){
log.error(getExceptionDetail(e));
return MyResponse.error(500, e.getMessage());
}
public String getExceptionDetail(Exception e) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(e.getClass() + System.getProperty("line.separator"));
stringBuilder.append(e.getLocalizedMessage() + System.getProperty("line.separator"));
StackTraceElement[] arr = e.getStackTrace();
for (int i = 0; i < arr.length; i++) {
stringBuilder.append(arr[i].toString() + System.getProperty("line.separator"));
}
return stringBuilder.toString();
}
}
4.编写测试类测试
@Slf4j
@RestController
@RequestMapping("exception")
public class ExceptionThrowController {
@GetMapping("/test/{value}")
private MyResponse test(@PathVariable String value){
if (StringUtils.isNotBlank(value)){
if (value.contains("qwe")) {
System.out.println("current num = " + value);
throw new HttpException(IExceptionEnum.REQUEST_URL_ERROR);
}
}
if (value.length() > 10){
System.out.println("current num = " + value);
throw new RuntimeException("num值长度为"+value.length()+",超过阈值10");
}
System.out.println("成功运行5");
return MyResponse.success(value);
}
}
5.resources目录下配置logback.xml
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n
UTF-8
./logs/info/log-stack.log
true
INFO
ACCEPT
DENY
./logs/info/log-stack.%d{yyyy-MM-dd}.log
30
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n
UTF-8
./logs/error/log-stack.log
true
ERROR
ACCEPT
DENY
./logs/error/log-stack.%d{yyyy-MM-dd}.log
30
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n
UTF-8
./logs/debug/log-stack.log
true
DEBUG
ACCEPT
DENY
./logs/debug/log-stack.%d{yyyy-MM-dd}.log
30
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n
UTF-8