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. 支持精准控制生效范围,无侵入、易维护,是企业级项目必备配置。
相关推荐
大傻^1 小时前
Spring AI Alibaba 企业级实战:从0到1构建智能客服系统
java·人工智能·后端·spring·springaialibaba
短剑重铸之日1 小时前
《ShardingSphere解读》11 解析引擎:SQL 解析流程应该包括哪些核心阶段?(上)
java·后端·spring·shardingsphere·分库分表
MekoLi292 小时前
MongoDB 新手完全指南:从入门到精通的实战手册
数据库·后端
会算数的⑨2 小时前
演进——从查日志到 AI 自治,企业监控体系的变迁
人工智能·分布式·后端·微服务·云原生
MekoLi292 小时前
ClickHouse 深度掌握与最佳实践指南
后端·架构
Leo8992 小时前
go从零单排之defer
后端
凛訫訫2 小时前
Java基础--面向对象高级(1)
后端
MekoLi292 小时前
ClickHouse 新手完全指南:从入门到架构师的最佳实践
后端·架构
I_Jln2 小时前
基于 Spring Cloud Gateway + Sa-Token 的架构为例,Token 异常的执行链路
后端