什么是 @ControllerAdvice 与 @RestControllerAdvice 之间的区别?

发布: (2025年12月23日 GMT+8 11:17)
6 分钟阅读
原文: Dev.to

Source: Dev.to

realNameHidden

了解 Spring Boot 中 @ControllerAdvice@RestControllerAdvice 的区别,提供清晰的解释和完整的 Java 示例。

介绍

想象你正在使用 Spring Boot 构建两个应用:

  • 传统 Web 应用 – 在浏览器中显示 HTML 页面。
  • REST API – 被移动应用或像 React 这样的前端框架消费。

现在假设出现了错误——比如用户未找到或请求无效。

你想在 每个控制器内部 处理错误吗?显然不想。

Spring 提供了一种简洁的方式来 全局 处理错误,即使用 @ControllerAdvice@RestControllerAdvice

初学者常问:

  • 这两个注解是一样的吗?
  • 什么时候该使用哪一个?
  • 为什么 REST API 的行为会不同?

在本博客中,我们将通过 清晰的概念和端到端的完整示例,解释 @ControllerAdvice@RestControllerAdvice 的区别,帮助你在实际的 Spring Boot 项目中自信地使用它们。

Source:

核心概念

什么是 @ControllerAdvice

@ControllerAdvice 用于在 控制器之间全局处理异常。可以把它看作是应用程序的 统一错误处理器

简易理解方式
与其让每个控制器各自处理错误,不如让一个统一的管理器为所有控制器处理。

关键点

  • @Controller(MVC 应用)配合使用
  • 通常返回 HTML 视图ModelAndView
  • 若想返回 JSON,需要配合 @ResponseBody

使用场景

  • Web 应用
  • 服务器端渲染页面(Thymeleaf、JSP)
  • 自定义错误页面

什么是 @RestControllerAdvice

@RestControllerAdvice 专为 REST API 设计。技术上相当于:

@ControllerAdvice + @ResponseBody

简易理解方式
与其返回错误页面,它返回 结构化的 JSON 数据

关键点

  • @RestController 配合使用效果最佳
  • 自动将响应转换为 JSON
  • 适用于微服务和 API

使用场景

  • REST API
  • 移动端或前端驱动的应用
  • 微服务架构

一目了然的关键区别

功能@ControllerAdvice@RestControllerAdvice
应用类型MVC / Web 应用REST API
默认响应HTML / 视图JSON
是否需要 @ResponseBody
最适合基于 UI 的应用API 与微服务

Source:

端到端代码示例(Java 21)

以下是 完整可运行的示例,展示了每个注解在实际场景中的使用方式。

示例 1:使用 @ControllerAdvice 的端到端 MVC 流程

步骤 1 – 自定义异常

public class PageNotFoundException extends RuntimeException {
    public PageNotFoundException(String message) {
        super(message);
    }
}

步骤 2 – MVC 控制器

@Controller
@RequestMapping("/pages")
public class PageController {

    @GetMapping("/{id}")
    public String getPage(@PathVariable int id) {
        if (id != 1) {
            throw new PageNotFoundException("Page not found with id: " + id);
        }
        return "home"; // returns an HTML page
    }
}

步骤 3 – 使用 @ControllerAdvice 的全局异常处理器

@ControllerAdvice
public class GlobalMvcExceptionHandler {

    @ExceptionHandler(PageNotFoundException.class)
    public String handlePageNotFound(PageNotFoundException ex, Model model) {
        model.addAttribute("errorMessage", ex.getMessage());
        return "error"; // resolves to error.html
    }
}

结果: 浏览器收到 HTML 错误页面 —— 实现了集中式错误处理,同时保持控制器代码简洁。

示例 2:使用 @RestControllerAdvice 的端到端 REST API 流程

步骤 1 – 自定义异常

public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

步骤 2 – 错误响应模型

import java.time.LocalDateTime;

public record ErrorResponse(
        int status,
        String message,
        LocalDateTime timestamp
) {}

步骤 3 – REST 控制器

@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping("/{id}")
    public String getUser(@PathVariable Long id) {
        if (!id.equals(1L)) {
            throw new ResourceNotFoundException("User not found with id: " + id);
        }
        return "User found";
    }
}

步骤 4 – 使用 @RestControllerAdvice 的全局异常处理器

@RestControllerAdvice
public class GlobalRestExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity handleResourceNotFound(
            ResourceNotFoundException ex) {

        ErrorResponse response = new ErrorResponse(
                HttpStatus.NOT_FOUND.value(),
                ex.getMessage(),
                LocalDateTime.now()
        );

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

结果(JSON 响应):

{
  "status": 404,
  "message": "User not found with id: 2",
  "timestamp": "2025-01-10T12:30:45"
}

Best Practices

  • 使用 @RestControllerAdvice 处理 REST API – 保证自动序列化(例如 JSON),并避免遗漏 @ResponseBody
  • 仅在 MVC 应用中使用 @ControllerAdvice – 当需要返回视图或模板时最为合适。
  • 创建一致的错误响应结构 – 有助于前端团队和 API 使用者统一处理错误。
  • 映射正确的 HTTP 状态码 – 对每种错误情况适当地使用 400404401500 等。
  • 避免首先使用通用 Exception 处理 – 应始终先处理具体异常,再回退到 Exception.class

常见错误需避免

  • ❌ 在 REST API 中使用 @ControllerAdvice 而未加 @ResponseBody
  • ❌ 从 REST API 返回 HTML 错误页面。
  • ❌ 在各个控制器内部处理异常,而不是集中处理。
  • ❌ 在 API 响应中暴露堆栈跟踪或内部细节。

结论

@ControllerAdvice@RestControllerAdvice 的区别在于 应用程序如何传递错误信息

  • 对于返回 HTML 的传统 Web 应用,使用 @ControllerAdvice
  • 对于返回 JSON(或其他基于响应体的格式)的 REST API,使用 @RestControllerAdvice

这两个注解都提供了集中、简洁且可扩展的异常处理方式。理解它们的区别可以让你的 Spring Boot 项目更易于维护,也更显专业——无论是在实际项目中还是面试时。

Back to Blog

相关文章

阅读更多 »