SpringBoot: 浅析 @ControllerAdvice 和 @RestControllerAdvice 之间的关系

315 阅读1分钟

两者之间的区别

@ControllerAdvice

  • 一种特殊的 @Component; 允许你将全局异常处理器、数据绑定、和全局数据(Model Attributes)放在一个地方。它可以用于处理所有由 @Controller 标注的控制器抛出的异常

@RestControllerAdvice

  • 等价于 @ControllerAdvice@ResponseBody 的组合,意味着返回的对象默认会通过 HttpMessageConverters 转换为 JSON 或 XML 格式,不需要额外的 @ResponseBody 注解。

类比

  • @Controller 是用于标记一个类作为 Spring MVC 的控制器,并且通常会返回视图 (HTML)
  • @RestController 是一个组合注解,相当于 @Controller 加上 @ResponseBody。它用于返回 JSON 或者 XML 数据,而不是视图

应用条件

  • 如果你的应用主要返回 JSON 或 XML 响应,那么使用 @RestControllerAdvice 会更简洁,因为它不需要在每个方法上添加 @ResponseBody 注解。

示例代码

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler({Exception.class})
    public RespBean handleGlobalExceptions(Exception ex) {
        log.error("异常:{}", ex.getMessage());

        if (ex instanceof GlobalException) {
            log.error("异常类型为: {}", (ex.getClass()));
            GlobalException globalException = (GlobalException) ex;
            return RespBean.error(globalException.getRespBeanEnum());
        } else if (ex instanceof BindException) {
            log.error("异常类型为: {}", (ex.getClass()));
            BindException bindException = (BindException) ex;
            RespBean respBean = RespBean.error(RespBeanEnum.BING_ERROR);
            respBean.setMsg("参数校验异常 ~~ 异常参数异常为:" + bindException.getBindingResult().getAllErrors().get(0).getDefaultMessage());
            return respBean;
        }
        return RespBean.error(RespBeanEnum.ERROR);
    }
}

也可以只是用 @ControllerAdvice,并且在异常处理方法上添加 @ResponseBody 注解,这样依然可以返回 JSON 响应

示例代码

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler({Exception.class})
    @ResponseBody
    public RespBean handleGlobalExceptions(Exception ex) {
        log.error("异常:{}", ex.getMessage());

        if (ex instanceof GlobalException) {
            log.error("异常类型为: {}", (ex.getClass()));
            GlobalException globalException = (GlobalException) ex;
            return RespBean.error(globalException.getRespBeanEnum());
        } else if (ex instanceof BindException) {
            log.error("异常类型为: {}", (ex.getClass()));
            BindException bindException = (BindException) ex;
            RespBean respBean = RespBean.error(RespBeanEnum.BING_ERROR);
            respBean.setMsg("参数校验异常 ~~ 异常参数异常为:" + bindException.getBindingResult().getAllErrors().get(0).getDefaultMessage());
            return respBean;
        }
        return RespBean.error(RespBeanEnum.ERROR);
    }
}