SpringBoot自定义全局异常处理器

SpringBoot自定义全局异常处理器

一、介绍

Springboot框架提供两个注解帮助我们十分方便实现全局异常处理器以及自定义异常

  • @ControllerAdvice@RestControllerAdvice(推荐)
  • @ExceptionHandler

二、实现

1. 定义全局异常处理器

定义GlobalExceptionHandler类,拦截所有异常。
@RestControllerAdvice注解使得你可以在GlobalExceptionHandler 中处理异常,@ExceptionHandle注解用于将指定异常绑定到处理的函数上。如下使用@ExceptionHandler(Exception.class)即对所有异常进行捕获处理。

language-java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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);
}
}
language-java
1
2
3
4
5
6
@Data
@AllArgsConstructor
public class RestErrorResponse implements Serializable {

private String errMessage;
}

事实上,写到这里已经可以用了,RestErrorResponse 用来承载错误信息到前端,因为@RestControllerAdvice已经包含了@ResponseBody

2. 自定义异常类

继承RuntimeException 异常类写一个自定义的异常类。这么做主要是能够使用自定义的枚举类来更优雅的抛出错误。

language-java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@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);
}

}
language-java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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 也要做一些修改,一方面处理自定义异常,另一方处理其余异常。

language-java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@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);
}
}

三、使用

在程序中任意地方抛出异常,controllerservicedao层都可以,比如

language-java
1
throw new RuntimeException("价格不能为空且必须大于0");

这时走的就是

language-java
1
2
@ExceptionHandler(Exception.class)
public RestErrorResponse exception(Exception e)

除此之外,可以这样抛出自定义异常,比如

language-java
1
XueChengPlusException.cast(CommonError.PARAMS_ERROR);
language-java
1
XueChengPlusException.cast("其他的消息");
language-java
1
throw new XueChengPlusException(CommonError.OBJECT_NULL.getErrMessage());
language-java
1
throw new XueChengPlusException("其他的消息");

这时走的就是

language-java
1
2
@ExceptionHandler(XueChengPlusException.class)
public RestErrorResponse customException(XueChengPlusException e)

四、疑问

Q:疑问,XueChengPlusException异常类继承自RuntimeException ,而RuntimeException 继承自Exception,为什么触发customException而不是exception?

在这个全局异常处理器中,当抛出一个XueChengPlusException异常时,它会被customException(XueChengPlusException e)方法处理,而不是exception(Exception e)方法。

这是因为Spring框架的异常处理机制会优先匹配最具体的异常类型。在您的代码中,XueChengPlusExceptionRuntimeException(以及Exception)的子类,因此它更具体。所以,当抛出一个XueChengPlusException异常时,Spring会优先调用处理XueChengPlusException的方法,而不是处理Exception的方法。

这种行为确实表明全局异常处理器有一定的优先级和覆盖逻辑。具体来说,处理器会优先处理更具体的异常类型,如果没有找到匹配的处理器,那么它会寻找处理更一般异常类型的处理器。

作者

Xiamu

发布于

2024-01-26

更新于

2024-08-11

许可协议

评论