注解@ControllerAdvice 与 @RestControllerAdvice还在傻傻的分不清吗❓

208 阅读4分钟

题记

生活不可能像你想象得那么好,但也不会像你想象得那么糟。

改变不了环境,就改变自己的心态。

起因

最近,闲来无事,就东瞅瞅西看看,也没发现什么。无意中翻了翻项目,看到项目中使用注解 @RestControllerAdvice,是用来做全局异常处理的,好多项目都使用这个了。最在我想关闭项目的时候,在一个角落中发现有一个项目中使用了@ControllerAdvice。话说@RestControllerAdvice@ControllerAdvice升级版,心想着还是有区别的,特此来整理分析下,希望大家多多指教!

进入正题

在我们使用的Spring 框架中,@ControllerAdvice 和 @RestControllerAdvice 是处理控制器层横切逻辑的核心注解,二者均基于 AOP 思想,用于集中管理全局异常处理、数据绑定等通用功能,但适用场景有所不同。

一、@ControllerAdvice:面向 MVC 视图的全局处理

@ControllerAdvice 是一个增强型注解,主要作用于传统 MVC 控制器(返回视图的控制器),用于抽取控制器中重复的逻辑,实现全局异常处理全局数据绑定请求预处理

  1. 全局异常处理
    配合 @ExceptionHandler 注解,统一捕获所有控制器抛出的异常,返回错误视图或跳转页面。

    @ControllerAdvice
    public class MvcGlobalExceptionHandler {
        // 处理空指针异常,返回错误页面
        @ExceptionHandler(NullPointerException.class)
        public ModelAndView handleNullPointerException(NullPointerException e) {
            ModelAndView mv = new ModelAndView();
            mv.addObject("errorMsg", "空指针异常:" + e.getMessage());
            mv.setViewName("error"); // 跳转到 error.html 视图
            return mv;
        }
    }
    
  2. 全局数据绑定
    通过 @ModelAttribute 定义全局数据,所有控制器和视图可直接访问(如系统配置信息)。

    @ControllerAdvice
    public class MvcGlobalData {
        @ModelAttribute("sysInfo")
        public Map<String, String> getSiteInfo() {
            Map<String, String> info = new HashMap<>();
            info.put("name", "xxx系统");
            info.put("version", "v1.0.1");
            return info; // 视图中可通过 ${sysInfo.name} 访问
        }
    }
    
  3. 范围控制 可通过属性限制作用范围,例如仅对特定包生效:

    @ControllerAdvice(basePackages = "com.example.mvc.controller")
    public class CustomMvcAdvice { ... }
    

二、@RestControllerAdvice:面向 REST API 的全局处理

@RestControllerAdvice 是 @ControllerAdvice 与 @ResponseBody 的组合注解,专门用于 RESTful 接口(返回 JSON/XML 等数据的控制器),其核心功能与 @ControllerAdvice 一致,但默认将处理结果转换为响应体(无需手动添加 @ResponseBody)。

  1. 全局异常处理
    统一捕获 REST 接口异常,返回 JSON 格式的错误信息。

    @RestControllerAdvice
    public class RestGlobalExceptionHandler {
        // 处理自定义业务异常
        @ExceptionHandler(BusinessException.class)
        public ResponseEntity<ErrorResult> handleBusinessException(BusinessException e) {
            ErrorResult error = new ErrorResult(e.getCode(), e.getMessage());
            return ResponseEntity.status(400).body(error);
        }
        
        // 处理参数校验异常
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public ErrorResult handleValidationException(MethodArgumentNotValidException e) {
            String msg = e.getBindingResult().getFieldError().getDefaultMessage();
            return new ErrorResult("400", msg); // 自动转为 JSON
        }
    }
    
    // 错误响应实体
    @Data
    class ErrorResult {
        private String code;
        private String message;
        // 构造方法省略
    }
    
  2. 全局数据绑定
    为所有 REST 接口注入通用数据(如请求 ID、时间戳)。

    @RestControllerAdvice
    public class RestGlobalData {
        @ModelAttribute("requestId")
        public String getRequestId() {
            return UUID.randomUUID().toString(); // 所有接口响应可包含此数据
        }
    }
    
  3. 范围控制
    同样支持限制作用范围,例如仅对 API 控制器生效:

    @RestControllerAdvice(basePackageClasses = ApiController.class)
    public class ApiAdvice { ... }
    

三、二者的核心区别

特性@ControllerAdvice@RestControllerAdvice
本质增强控制器的通用逻辑@ControllerAdvice + @ResponseBody
返回值处理需手动配置视图解析(返回页面)自动将返回值转为 JSON/XML 响应体
适用场景传统 MVC 视图渲染(如 JSP/Thymeleaf)RESTful API 接口(前后端分离)
异常处理返回形式通常返回错误页面通常返回 JSON 错误信息

四、逻辑图

tongyi-mermaid-2025-08-14-150001.png

  1. 客户端请求进入DispatcherServlet接收请求

  2. 模型预处理:执行所有@ModelAttribute方法

  3. 控制器执行:调用匹配的控制器方法

  4. 异常检测

    • 出现异常 → 查找匹配的@ExceptionHandler
    • 无异常 → 返回正常结果
  5. 结果处理

    • @ControllerAdvice:视图渲染
    • @RestControllerAdvice:JSON序列化

总结

  1. @ControllerAdvice 主要适用于传统 MVC 项目,专注于视图层的全局处理,需通过视图解析器返回页面。如果需要返回json格式的数据,需要和注解 @ResponseBody 进行搭配使用。

  2. @RestControllerAdvice 适用于前后端分离的 RESTful 项目,自动将处理结果转为响应体,比如说json或者xml格式的数据,从而达到简化效果。

  3. 二者均体现了 “集中管理横切逻辑” 的设计思想,减少代码冗余,提升项目可维护性。主要还是一点,根据需求来选择合适的注解,主要是自己喜欢就好,哈哈!

展望

祝愿看到这篇文章的掘友:

工作顺心,收入翻倍,灵感不断,好运连连!

愿前程似锦,未来可期,不负韶华,不负自己。