SpringBoot 全局异常处理器实现

主流两种方案:@RestControllerAdvice + @ExceptionHandler (推荐),分统一返回结果、自定义业务异常、全局异常捕获、分层拦截完整实现。

一、前置:统一响应实体

项目接口统一返回格式,便于前端处理。

java 复制代码
import lombok.Data;

/**
 * 全局统一返回结果
 */
@Data
public class Result<T> {
    // 响应码:200成功,500系统异常,自定义业务码自行定义
    private Integer code;
    // 响应信息
    private String message;
    // 响应数据
    private T data;

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

    public static <T> Result<T> success() {
        return success(null);
    }

    // 失败响应
    public static <T> Result<T> fail(Integer code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        result.setData(null);
        return result;
    }

    public static <T> Result<T> fail(String message) {
        return fail(500, message);
    }
}

二、自定义业务异常

区分系统异常 和业务异常,精准捕获业务报错。

java 复制代码
/**
 * 自定义业务异常
 */
public class BusinessException extends RuntimeException {
    private Integer code;

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public BusinessException(String message) {
        super(message);
        this.code = 500;
    }

    public Integer getCode() {
        return code;
    }
}

三、全局异常处理器(核心)

使用 @RestControllerAdvice 作用于所有 Controller ,配合 @ExceptionHandler 拦截指定异常。

java 复制代码
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 * RestControllerAdvice = ControllerAdvice + ResponseBody
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 1. 捕获自定义业务异常(优先匹配)
    @ExceptionHandler(BusinessException.class)
    public Result<?> businessExceptionHandler(BusinessException e) {
        return Result.fail(e.getCode(), e.getMessage());
    }

    // 2. 捕获参数校验异常(如 @Valid 校验失败)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> validExceptionHandler(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(400, "参数错误:" + msg);
    }

    // 3. 捕获空指针异常
    @ExceptionHandler(NullPointerException.class)
    public Result<?> nullPointerExceptionHandler() {
        return Result.fail(500, "系统空指针异常,请联系管理员");
    }

    // 4. 兜底:捕获所有未知异常(最后执行)
    @ExceptionHandler(Exception.class)
    public Result<?> exceptionHandler(Exception e) {
        // 生产环境可打印日志 e.printStackTrace()
        return Result.fail(500, "系统繁忙,请稍后重试");
    }
}

注解说明

  1. @RestControllerAdvice
    • 全局切面,拦截所有 @RestController / @Controller 接口
    • 自带 @ResponseBody,返回 JSON 格式
  2. @ExceptionHandler(异常类.class)
    • 指定要拦截的异常类型,精准异常优先于父类异常

四、使用测试

1. 编写测试 Controller

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

@RestController
public class TestController {

    // 测试业务异常
    @GetMapping("/test/biz")
    public Result<?> testBiz() {
        throw new BusinessException(1001, "用户名不存在");
    }

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

    // 测试普通异常
    @GetMapping("/test/error")
    public Result<?> testError() {
        int a = 1 / 0;
        return Result.success();
    }
}

2. 调用接口效果

  • /test/biz → 返回 code:1001, message:用户名不存在
  • /test/null → 返回空指针提示
  • /test/error → 被 Exception 兜底拦截

五、扩展常用场景

1. 拦截 SpringMVC 404/405 等状态异常

需在 application.yml 开启异常转发:

yaml 复制代码
spring:
  mvc:
    throw-exception-if-no-handler-found: true
  resources:
    add-mappings: false

新增异常处理方法:

java 复制代码
// 拦截404找不到接口异常
@ExceptionHandler(NoHandlerFoundException.class)
public Result<?> noHandlerFoundException() {
    return Result.fail(404, "请求接口不存在");
}

2. 统一日志打印(生产必备)

异常处理器中加入日志,方便排查问题:

java 复制代码
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Result<?> exceptionHandler(Exception e) {
        log.error("系统未知异常:", e);
        return Result.fail(500, "系统繁忙,请稍后重试");
    }
}

六、关键点总结

  1. 异常优先级 :具体异常 > 自定义异常 > Exception 兜底
  2. 适用范围 :@RestControllerAdvice 只拦截Controller 层异常,Service/工具类主动抛异常依然会被捕获
  3. 规范建议 :业务场景统一抛 BusinessException,系统异常由全局处理器统一封装
  4. 排除拦截 :如需部分 Controller 不生效,可配合 @ControllerAdvice(basePackages = "com.xxx.controller") 指定包范围
相关推荐
Escalating_xu1 小时前
【Linux 网络编程】五种 I/O 模型与非阻塞 I/O:从“等数据”到正确处理 EAGAIN
java·linux·网络
程序猿乐锅1 小时前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
Java后端的Ai之路1 小时前
【AIAgent开发】-Agent工具封装成CLI(纯干货!!!)
java·javascript·人工智能·agent·cli
AntsData2 小时前
用 12K+ 条亚马逊评论信号,定位机械键盘下一版该改什么
java·大数据·计算机外设
code2cat2 小时前
【随笔】连续批处理:长短请求怎样在迭代之间补位
java·人工智能·后端·大语言模型·vllm
最强小杰2 小时前
DeepSeek V4 Flash + Codex CLI 接入教程:原生 Responses API 适配,从配置到跑通收藏这篇就够了(2026)
java·前端·python·ai
Flynn Liang2 小时前
Spring AI 2.0 深度解析:ChatClient、Advisor 链与 MCP——Java 工程师的 AI 落地最优解
java·人工智能·spring·大模型·架构设计·spring ai
灿飞2 小时前
Kotlin与Java虚拟机六:基础与类型系统:一切皆对象,但对象有代价
java·kotlin
计算机毕设定制辅导-无忧学长3 小时前
《基于微信小程序健康习惯激励系统设计与实现》
java·spring boot·mysql·微信小程序·uniapp·健康习惯激励系统
掘金者阿豪3 小时前
SQL Server数据迁移完成后,凌晨的数据库告警该怎么查?
前端·后端