JAVA 8
Spring Boot 2.5.3
---
访问Spring Web请求时,可能会出现一些异常(JDK或其它包定义 或 项目自定义的异常),此时,默认情况下,返回给 调用方的是默认信息,比如:
为了 统一响应信息格式 等需求,因此,需要对这些异常 做统一处理。
相关注解:
@ControllerAdvice + @ResponseBody 或 @RestControllerAdvice
@ExceptionHandler
注解源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice // 看这里
@ResponseBody
public @interface RestControllerAdvice {
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
示例代码:
拦截 org.lib.mysqlhello 包(项目根包)下所有 Exception异常——范围很大。
/**
* 统一异常处理
* 使用切面时,如果处理了异常 并且 返回了值,则不会执行到这里
* @author ben
* @date 2021-08-22 13:02:34 CST
*/
@ControllerAdvice(value = {"org.lib.mysqlhello"})
@ResponseBody
// 同上面两个注解等效
//@RestControllerAdvice(value = {"org.lib.mysqlhello"})
@Slf4j
public class AppExceptionHandler {
/**
* 注解 ResponseBody 是关键
* @author ben
* @date 2021-08-22 14:06:17 CST
* @param e
* @return
*/
@ExceptionHandler(value = {Exception.class})
ResultVO<Object> handleException(Exception e) {
log.error("发生异常: e={}, e.message={}", e.getClass(), e.getMessage());
return ResultVO.getFailed(500, "发生异常-AppExceptionHandler", null);
}
}
注:上面的 ResultVO类是 定义的 项目统一返回类;返回的 第三个参数为 null。
上面只有一个 @ExceptionHandler ,实际使用时 可以定义多个,用来拦截不同的 Exception。
存在多个时,还需要考虑到 它们的顺序。
测试结果:
官方文档 Spring Framework Documentation->Web Servlet 中会有详细介绍:
其中,对 @ExceptionHandler 方法的 入参、返回值 有做具体介绍:
使用期间的错误:
一开始使用了 @ControllerAdvice,但 没有同时使用@ResponseBody,此时出现了错误——收不到@ExceptionHandler函数中定义的 返回值,此时返回 S.B.默认错误内容。
添加 @ResponseBody 后,问题得到解决——可以到 类上、也可以添加到 方法上,均可。
或者,使用 @RestControllerAdvice 替换两者。
参考文档
1、拦截机制中Aspect、ControllerAdvice、Interceptor、Fliter之间的区别详解
理解 这个顺序很重要。
2、springboot使用多个@RestControllerAdvice时的拦截顺序
4、