文章目录
一、介绍
Springboot
框架提供两个注解帮助我们十分方便实现全局异常处理器
以及自定义异常
。
@ControllerAdvice
或@RestControllerAdvice
(推荐)@ExceptionHandler
二、实现
1. 定义全局异常处理器
定义GlobalExceptionHandler
类,拦截所有异常。
@RestControllerAdvice
注解使得你可以在GlobalExceptionHandler
中处理异常,@ExceptionHandle
注解用于将指定异常绑定到处理的函数上。如下使用@ExceptionHandler(Exception.class)
即对所有异常进行捕获处理。
java
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestErrorResponse exception(Exception e){
//record log
log.error("系统异常{}", e.getMessage(),e);
//decode errorException
String errMessage = "系统异常";
return new RestErrorResponse(errMessage);
}
}
java
@Data
@AllArgsConstructor
public class RestErrorResponse implements Serializable {
private String errMessage;
}
事实上,写到这里已经可以用了,RestErrorResponse
用来承载错误信息到前端,因为@RestControllerAdvice
已经包含了@ResponseBody
。
2. 自定义异常类
继承RuntimeException
异常类写一个自定义的异常类。这么做主要是能够使用自定义的枚举类来更优雅的抛出错误。
java
@Data
public class XueChengPlusException extends RuntimeException {
private String errMessage;
public XueChengPlusException() {
super();
}
public XueChengPlusException(String errMessage) {
super(errMessage);
this.errMessage = errMessage;
}
public static void cast(CommonError commonError){
throw new XueChengPlusException(commonError.getErrMessage());
}
public static void cast(String errMessage){
throw new XueChengPlusException(errMessage);
}
}
java
@Getter
public enum CommonError {
UNKOWN_ERROR("执行过程异常,请重试。"),
PARAMS_ERROR("非法参数"),
OBJECT_NULL("对象为空"),
QUERY_NULL("查询结果为空"),
REQUEST_NULL("请求参数为空");
private String errMessage;
private CommonError( String errMessage) {
this.errMessage = errMessage;
}
}
同时,对于GlobalExceptionHandler
也要做一些修改,一方面处理自定义异常,另一方处理其余异常。
java
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(XueChengPlusException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestErrorResponse customException(XueChengPlusException e){
//record log
log.error("系统异常{}", e.getErrMessage(),e);
//decode errorException
String errMessage = e.getErrMessage();
return new RestErrorResponse(errMessage);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestErrorResponse exception(Exception e){
//record log
log.error("系统异常{}", e.getMessage(),e);
//decode errorException
String errMessage = CommonError.UNKOWN_ERROR.getErrMessage();
return new RestErrorResponse(errMessage);
}
}
三、使用
在程序中任意地方抛出异常,controller
、service
、dao
层都可以,比如
java
throw new RuntimeException("价格不能为空且必须大于0");
这时走的就是
java
@ExceptionHandler(Exception.class)
public RestErrorResponse exception(Exception e)
除此之外,可以这样抛出自定义异常,比如
java
XueChengPlusException.cast(CommonError.PARAMS_ERROR);
java
XueChengPlusException.cast("其他的消息");
java
throw new XueChengPlusException(CommonError.OBJECT_NULL.getErrMessage());
java
throw new XueChengPlusException("其他的消息");
这时走的就是
java
@ExceptionHandler(XueChengPlusException.class)
public RestErrorResponse customException(XueChengPlusException e)
四、疑问
Q:疑问,XueChengPlusException异常类继承自RuntimeException ,而RuntimeException 继承自Exception,为什么触发customException而不是exception?
在这个全局异常处理器中,当抛出一个XueChengPlusException
异常时,它会被customException(XueChengPlusException e)
方法处理,而不是exception(Exception e)
方法。
这是因为Spring框架的异常处理机制会优先匹配最具体的异常类型。在您的代码中,XueChengPlusException
是RuntimeException
(以及Exception
)的子类,因此它更具体。所以,当抛出一个XueChengPlusException
异常时,Spring会优先调用处理XueChengPlusException
的方法,而不是处理Exception
的方法。
这种行为确实表明全局异常处理器有一定的优先级和覆盖逻辑。具体来说,处理器会优先处理更具体的异常类型,如果没有找到匹配的处理器,那么它会寻找处理更一般异常类型的处理器。