当前位置: 首页 > news >正文

RestControllerAdvice 和 ControllerAdvice 两个注解的区别与联系

它们都用于实现全局的通用处理逻辑,主要应用在以下三个方面:

  1. 全局异常处理: 使用 @ExceptionHandler 注解的方法。
  2. 全局数据绑定: 使用 @InitBinder 注解的方法。
  3. 全局数据预处理: 使用 @ModelAttribute 注解的方法。

联系:

  1. 核心功能相同: 两者都提供了上述三种全局处理的能力。我们可以将原本分散在多个 Controller 中的通用异常处理、数据绑定规则、公共 Model 属性提取到标有这两个注解的类中统一管理。
  2. 都是 @Component: 从 Spring 的角度看,它们都是 @Component 的特殊化注解。这意味着 Spring 容器会自动扫描并注册这些 Bean。
  3. @RestControllerAdvice@ControllerAdvice 的组合注解: 这是最关键的联系。@RestControllerAdvice 本质上是 @ControllerAdvice@ResponseBody 两个注解的组合

查看 @RestControllerAdvice 的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice // <--- 包含了 @ControllerAdvice
@ResponseBody   // <--- 包含了 @ResponseBody
public @interface RestControllerAdvice {// ... 注解属性定义 ...
}

区别 (核心在于 @ResponseBody):

这个组合带来的核心区别在于对包含 @ExceptionHandler 注解的方法的返回值处理方式不同:

  1. @ControllerAdvice:

    • 如果其内部的 @ExceptionHandler 方法没有添加 @ResponseBody 注解,那么其返回值通常会被视图解析器(ViewResolver)处理。会返回一个 String 类型的视图名,或者一个 ModelAndView 对象,用于页面跳转或渲染。
    • 如果其内部的 @ExceptionHandler 方法添加了 @ResponseBody 注解,就和 @RestControllerAdvice 中的方法一样了,返回值会直接写入 HTTP 响应体中,通常是 JSON 或 XML 格式。
  2. @RestControllerAdvice:

    • 由于它自带了 @ResponseBody 注解,所以其内部所有 @ExceptionHandler 方法(以及 @ModelAttribute 方法)的返回值默认就会被 Spring MVC 当作响应体内容处理,通过 HttpMessageConverter 进行序列化(例如转为 JSON)并写入 Response Body。
    • 它特别适用于构建 RESTful API 的全局异常处理,因为 REST API 通常期望返回的是数据(如 JSON),而不是一个 HTML 视图。

总结与选择:

特性@ControllerAdvice@RestControllerAdvice (@ControllerAdvice + @ResponseBody)
核心目的全局 Controller 增强 (异常、数据绑定、模型属性)全局 Controller 增强 (异常、数据绑定、模型属性)
基础注解@Component@Component
组合@ControllerAdvice + @ResponseBody
@ExceptionHandler 返回值默认处理视图解析 (返回视图名/ModelAndView)写入响应体 (通过 HttpMessageConverter 转为 JSON/XML 等)
适用场景1. 传统的 Spring MVC 应用 (返回 HTML 视图)
2. 需要混合处理(部分返回视图,部分加 @ResponseBody 返回 JSON)的应用
3. 只用于全局 @InitBinder 或不返回数据的 @ModelAttribute
1. RESTful API (主要返回 JSON/XML 数据)
2. 所有全局异常都希望返回 JSON/XML 错误结构体

简单来说:

  • 如果你在构建一个传统的、主要返回 HTML 页面的 Spring MVC 应用,或者需要灵活处理部分返回视图、部分返回 JSON 的情况,使用 @ControllerAdvice。如果某个异常处理器需要返回 JSON,可以在该方法上单独加 @ResponseBody
  • 如果你在构建一个纯粹的 RESTful API,所有的 Controller 和异常处理都期望返回 JSON 或 XML 数据,那么使用 @RestControllerAdvice 更方便,因为它省去了在每个 @ExceptionHandler 方法上都写 @ResponseBody 的麻烦。

示例:

使用 @ControllerAdvice (可能返回视图)

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;@ControllerAdvice
public class GlobalWebExceptionHandler {private static final Logger log = LoggerFactory.getLogger(GlobalWebExceptionHandler.class);@ExceptionHandler(Exception.class) // 处理所有未捕获的异常public ModelAndView handleGenericException(Exception e) {log.error("Unhandled exception occurred", e); // 建议记录完整堆栈ModelAndView mav = new ModelAndView();mav.addObject("errorMessage", "服务器内部错误,请稍后再试。");mav.setViewName("error"); // 返回名为 "error" 的视图 (e.g., error.html)return mav;}@ExceptionHandler(CustomBusinessException.class)// 如果这个特定的异常想返回JSON,需要单独加 @ResponseBody// @ResponseBodypublic ModelAndView handleBusinessException(CustomBusinessException e) {log.warn("Business exception: {}", e.getMessage());ModelAndView mav = new ModelAndView();mav.addObject("errorMessage", e.getMessage());mav.setViewName("business-error");return mav;}
}

使用 @RestControllerAdvice (返回 JSON)

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;// 注意这里是 @RestControllerAdvice
@RestControllerAdvice
public class GlobalApiExceptionHandler {private static final Logger log = LoggerFactory.getLogger(GlobalApiExceptionHandler.class);// 返回值会自动通过 HttpMessageConverter 转为 JSON (或其他协商格式)@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleGenericApiException(Exception e) {log.error("Unhandled API exception occurred", e);ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Internal Server Error", "An unexpected error occurred.");return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);}@ExceptionHandler(ResourceNotFoundException.class)public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException e) {log.warn("Resource not found: {}", e.getMessage());ErrorResponse error = new ErrorResponse(HttpStatus.NOT_FOUND.value(), "Not Found", e.getMessage());return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);}// 简单的错误响应体类public static class ErrorResponse {private int status;private String error;private String message;public ErrorResponse(int status, String error, String message) {this.status = status;this.error = error;this.message = message;}// Getters...public int getStatus() { return status; }public String getError() { return error; }public String getMessage() { return message; }}
}// 假设的自定义异常
class ResourceNotFoundException extends RuntimeException {public ResourceNotFoundException(String message) { super(message); }
}
class CustomBusinessException extends RuntimeException {public CustomBusinessException(String message) { super(message); }
}

相关文章:

  • 二十、FTP云盘
  • Operator 开发入门系列(一):Hello World
  • 【Java学习笔记】标识符和保留字
  • NLP高频面试题(四十七)——探讨Transformer中的注意力机制:MHA、MQA与GQA
  • 火山云如何运营
  • Vscode开发Vue项目NodeJs启动报错处理
  • 【Rust基础】crossbeam带来的阻塞问题
  • 大模型-mcp学习
  • 基于Django实现的图书分析大屏系统项目
  • 为什么要做种草商城
  • MAPLE:编码从自我为中心的视频中学习的灵巧机器人操作先验
  • LeetCode之两数之和
  • 驱动-原子操作
  • 《Java 泛型的作用与常见用法详解》
  • 【JavaScript】二十四、JS的执行机制事件循环 + location + navigator + history
  • 做Data+AI的长期主义者,加速全球化战略布局
  • 4月17日复盘
  • Kettle和Canal
  • 【AI论文】Genius:一种用于高级推理的可泛化和纯无监督的自我训练框架
  • 使用FastAPI构建高效、优雅的RESTful API
  • 国家网信办举办在欧中资企业座谈会,就数据跨境流动等进行交流
  • 揭秘神舟十九号返回舱“软着陆”关键:4台发动机10毫秒内同时点火
  • 国务院安委会对辽宁辽阳一饭店重大火灾事故查处挂牌督办
  • 千亿市值光储龙头董事长向母校合肥工业大学捐赠1亿元
  • 央媒谈多地景区试水“免费开放”:盲目跟风会顾此失彼
  • 学大教育:去年净利润1.797亿元,学习中心增加约60所