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. 支持精准控制生效范围,无侵入、易维护,是企业级项目必备配置。
相关推荐
Mahir088 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
IT_陈寒12 小时前
Redis缓存击穿把我整不会了,原来还有这手操作
前端·人工智能·后端
kyriewen12 小时前
面试官让我查各部门工资最高的员工,我用AI三秒写出窗口函数,他愣了
后端·mysql·面试
文心快码BaiduComate12 小时前
干货|Comate Harness Engineering工程实践指南
前端·后端·程序员
光辉GuangHui12 小时前
Agent Skill 也需要测试:如何搭建 Skill 评估框架
前端·后端·llm
我是谁的程序员13 小时前
Mac 上生成 AppStoreInfo.plist 文件,App Store 上架
后端·ios
irving同学4623813 小时前
Node 后端实战:JWT 认证与生产级错误处理
前端·后端
Master_Azur13 小时前
单元测试——Junit单元测试框架
后端
用户83562907805113 小时前
使用 Python 进行 Word 邮件合并
后端
用户83562907805113 小时前
Python 操作 PowerPoint OLE 对象
后端·python