Spring Boot @RestControllerAdvice:统一异常处理的利器

Spring Boot @RestControllerAdvice:统一异常处理的利器

@RestControllerAdviceSpring Boot 专为 RESTful 接口设计的全局增强注解 ,它是 @ControllerAdvice + @ResponseBody 的组合注解,核心作用是全局统一处理 Controller 层的异常、全局绑定数据、全局预处理请求参数 ,是企业级项目中统一接口响应、统一异常处理的标准方案。


一、核心作用(3大场景)

  1. 全局统一异常处理(最常用,90%的使用场景)
  2. 全局数据绑定(所有接口共享公共参数)
  3. 全局请求参数预处理(参数格式化、去空格、类型转换)

二、环境依赖

只需引入 Spring Web 依赖(Spring Boot 项目默认已包含):

xml 复制代码
<!-- Maven -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

三、最常用:全局统一异常处理(实战必用)

步骤1:定义统一响应体

REST 接口需要固定返回格式,先封装通用结果类:

arduino 复制代码
import lombok.Data;

/**
 * 统一API响应结果
 */
@Data
public class Result<T> {
    private int code;    // 响应码
    private String msg;  // 响应消息
    private T data;      // 响应数据

    // 成功响应
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMsg("操作成功");
        result.setData(data);
        return result;
    }

    // 失败响应
    public static <T> Result<T> fail(int code, String msg) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

步骤2:创建全局异常处理器

使用 @RestControllerAdvice + @ExceptionHandler 捕获所有接口异常:

kotlin 复制代码
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.resource.NoResourceFoundException;

/**
 * 全局异常处理器(所有REST接口生效)
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    // ====================== 1. 捕获自定义业务异常 ======================
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        return Result.fail(e.getCode(), e.getMessage());
    }

    // ====================== 2. 捕获参数校验异常(@Valid) ======================
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleValidException(MethodArgumentNotValidException e) {
        // 获取第一个校验错误信息
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(400, message);
    }

    // ====================== 3. 捕获404资源不存在异常 ======================
    @ExceptionHandler(NoResourceFoundException.class)
    public Result<Void> handle404Exception() {
        return Result.fail(404, "请求资源不存在");
    }

    // ====================== 4. 捕获空指针异常 ======================
    @ExceptionHandler(NullPointerException.class)
    public Result<Void> handleNullPointerException() {
        return Result.fail(500, "系统异常:空指针错误");
    }

    // ====================== 5. 捕获所有未匹配的异常(兜底) ======================
    @ExceptionHandler(Exception.class)
    public Result<Void> handleGlobalException(Exception e) {
        e.printStackTrace(); // 打印日志
        return Result.fail(500, "服务器内部错误");
    }
}

步骤3:自定义业务异常(可选)

scala 复制代码
import lombok.Data;

/**
 * 自定义业务异常
 */
@Data
public class BusinessException extends RuntimeException {
    private int code;
    private String msg;

    public BusinessException(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

步骤4:测试接口

typescript 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    // 测试业务异常
    @GetMapping("/test")
    public Result<String> test() {
        throw new BusinessException(401, "用户未登录");
    }

    // 测试空指针
    @GetMapping("/null")
    public Result<String> testNull() {
        String str = null;
        str.length();
        return Result.success("");
    }
}

效果

所有接口的异常都会被统一捕获,返回标准JSON格式,前端无需处理各种混乱的异常响应。


四、精准控制生效范围(进阶)

默认 @RestControllerAdvice所有Controller生效,可通过属性指定生效包/类:

less 复制代码
// 1. 只对指定包下的Controller生效(推荐)
@RestControllerAdvice(basePackages = "com.example.project.controller")

// 2. 只对指定类生效
@RestControllerAdvice(assignableTypes = {UserController.class, OrderController.class})

// 3. 按类所在包生效
@RestControllerAdvice(basePackageClasses = UserController.class)

五、其他扩展用法

1. 全局数据绑定(所有接口共享公共数据)

使用 @ModelAttribute,所有接口都能获取到绑定的数据:

kotlin 复制代码
@RestControllerAdvice
public class GlobalDataConfig {
    // 所有接口都能获取到 appName 字段
    @ModelAttribute("appName")
    public String appName() {
        return "SpringBoot 项目";
    }
}

2. 全局参数预处理(格式化参数)

使用 @InitBinder,统一处理请求参数(如去空格、日期格式化):

typescript 复制代码
@RestControllerAdvice
public class GlobalParamHandler {
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 字符串参数自动去空格
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }
}

六、关键注意事项

  1. 匹配优先级@ExceptionHandler 会优先匹配精确异常 ,再匹配父类异常(兜底用 Exception.class)。

  2. 扫描生效 :全局异常处理器必须被 Spring 扫描到(放在主启动类同级/子包下)。

  3. 与 @ControllerAdvice 区别

    1. @RestControllerAdvice:返回 JSON 数据(REST接口专用);
    2. @ControllerAdvice:返回 页面/视图(传统Web项目用)。
  4. 无侵入性:无需修改原有Controller代码,全局统一处理。


总结

  1. @RestControllerAdvice 是 Spring Boot REST 接口全局增强神器 ,核心用于统一异常处理
  2. 搭配 @ExceptionHandler 可捕获所有接口异常,返回标准化响应;
  3. 支持精准控制生效范围,无侵入、易维护,是企业级项目必备配置。
相关推荐
她的男孩23 分钟前
Spring Boot 接 Flowable 工作流:用 3 个注解搭一个请假审批流程
java·后端·架构
爱读源码的大都督29 分钟前
Claude Code源码分析(三):为什么系统提示词中需要有tools呢?
前端·人工智能·后端
爱勇宝34 分钟前
Claude Code 被曝暗藏“隐形检测”代码:封代理不是最可怕的,可怕的是你根本不知道它在干什么
前端·后端·程序员
ITOM运维行者1 小时前
从零搭建企业级服务器监控体系:踩坑实录与架构设计
前端·后端
用户4099322502121 小时前
Vue状态管理入门第四章:组合式store和SSR风险
前端·vue.js·后端
用户34232323763171 小时前
SPI 通信与高速外设驱动详解
后端
魏祖潇1 小时前
SDD 完整指南——Spec 端打底、Story 端交付、留白区
人工智能·后端
feelmylife592 小时前
消息队列可靠投递与幂等消费 -- 从"消息丢了"到"消息别重复"的完整工程实践
后端
雪隐2 小时前
个人电脑玩AI-10让5060 Ti给你打工——部署 Odysseus:终于有个能打的"AI管家"了
人工智能·后端
copyer_xyf2 小时前
FastAPI 如何连接 MySQL
后端·python