引言
之前发表过一篇 SpringBoot 对 controller 层捕获全局异常并处理的方法(@ControllerAdvice 和 @ExceptionHandler),介绍了如何在 SpringBoot 工程中对 Controller 配置全局异常处理。后来在实际工程中,又有了如下需求:有些接口在发生异常时,需要持久化错误信息,而有的接口则不需要。如果使用了全局异常处理,那每次发生了异常,还需要判断是哪个接口发生的异常,进而选择是否持久化错误日志。那能不能对全局异常进行配置,对不同类型的接口使用不同的全局异常进行处理呢?
经过查阅文档发现,Spring 提供了对 @ControllerAdvice 注解的配置,我们可以通过配置 @ControllerAdvice 指定拦截范围。
@ControllerAdvice 指定 Controller 范围
根据 API,我们可以看到注解 @ControllerAdvice 有如下几种配置:
basePackages
1 2 3 4
|
@ControllerAdvice(basePackages = {"cn.myz.demo.controller"}) public class GlobalExceptionHandler {}
|
basePackages
:指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。其中上面两种等价于 basePackages。
basePackageClasses
1 2
| @ControllerAdvice(basePackageClasses = {MyController1.class}) public class GlobalExceptionHandler {}
|
basePackageClasses
:是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。
assignableTypes
1 2
| @ControllerAdvice(assignableTypes = {MyController1.class}) public class GlobalExceptionHandler {}
|
assignableTypes
:指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理。
annotations
1 2
| @ControllerAdvice(annotations = {RestController.class}) public class GlobalExceptionHandler {}
|
annotations
:指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理。
例子
这里我用 assignableTypes 配置指定的 Controller 进行测试。
创建三个 Controller
1 2 3 4 5 6 7 8
| @Controller public class MyController1 {
@RequestMapping(value = "/test1") public void test1() { throw new BusinessException("1", "test1 错误"); } }
|
1 2 3 4 5 6 7
| @Controller public class MyController2 { @RequestMapping(value = "/test2") public void test1() { throw new BusinessException("2", "test2 错误"); } }
|
1 2 3 4 5 6 7
| @Controller public class MyController3 { @RequestMapping(value = "/test3") public void test1() { throw new BusinessException("3", "test3 错误"); } }
|
其中,BusinessException 是我自定义的异常类。
创建两个全局异常处理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @ControllerAdvice(assignableTypes = {MyController1.class}) @Slf4j public class GlobalExceptionHandler1 {
@ResponseBody @ExceptionHandler(value = Exception.class) public String exceptionHandler(HttpServletRequest httpServletRequest, Exception e) { log.error("GlobalExceptionHandler1 服务错误"); return "GlobalExceptionHandler1 服务错误"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @ControllerAdvice(assignableTypes = {MyController2.class}) @Slf4j public class GlobalExceptionHandler2 {
@ResponseBody @ExceptionHandler(value = Exception.class) public String exceptionHandler(HttpServletRequest httpServletRequest, Exception e) { log.error("GlobalExceptionHandler2 服务错误"); return "GlobalExceptionHandler2 服务错误"; } }
|
分别调用接口,查看错误日志
调用 localhost:8080/test1
返回:GlobalExceptionHandler1 服务错误
即 MyController1 异常被 GlobalExceptionHandler1 全局异常类捕获。
调用 localhost:8080/test2
返回:GlobalExceptionHandler2 服务错误
即 MyController2 异常被 GlobalExceptionHandler2 全局异常类捕获。
调用 localhost:8080/test3
返回:
1 2 3 4 5 6 7
| { "timestamp": "2019-03-15T06:40:06.224+0000", "status": 500, "error": "Internal Server Error", "message": "No message available", "path": "/test3" }
|
即 MyController3 异常没有被全局异常捕获。
以上就是全局异常的分类处理。
站在前人的肩膀上前行,感谢以下资料的支持。