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