SpringBoot实战:搭建简易全局异常处理器

举报
JiHua 发表于 2026/10/15 11:10:04 2026/10/15
【摘要】 在后端项目开发中,异常处理是保障接口稳定性、统一返回格式的关键。很多新手习惯在每个接口中写大量try-catch,代码冗余且返回信息杂乱。本文使用Spring Boot搭建全局异常处理器,实现自定义业务异常捕获、参数校验异常拦截、未知异常兜底,统一JSON返回结构,附带完整代码,可直接在华为云ECS部署测试,适合Java后端入门实战。

前言

日常开发接口时,程序总会出现各类异常:前端传参不符合规则、业务逻辑校验失败、空指针、数据库查询异常等。如果不做统一处理,异常堆栈会直接返回给前端,不仅界面展示不友好,还会泄露服务内部信息,存在安全隐患。

不少初学者会在每一个Controller方法内部写try-catch捕获异常,这种写法会造成大量重复代码,维护成本很高。Spring Boot提供了@RestControllerAdvice注解,可以实现全局异常捕获,一次性拦截所有Controller抛出的异常,统一封装返回结果。

本文从零搭建Demo项目,实现一套通用全局异常处理方案,覆盖自定义业务异常、JSR303参数校验异常、系统未知异常三类场景。

技术栈

  • Java 17
  • SpringBoot 2.7.x
  • spring-boot-starter-web
  • spring-boot-starter-validation(参数校验)

Maven依赖 pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
</dependencies>

1. 统一返回实体类 Result.java

public class Result<T> {
    private Integer code;
    private String msg;
    private T data;

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

    public static <T> Result<T> fail(Integer code, String msg) {
        Result<T> r = new Result<>();
        r.setCode(code);
        r.setMsg(msg);
        r.setData(null);
        return r;
    }

    // getter & setter
    public Integer getCode() { return code; }
    public void setCode(Integer code) { this.code = code; }
    public String getMsg() { return msg; }
    public void setMsg(String msg) { this.msg = msg; }
    public T getData() { return data; }
    public void setData(T data) { this.data = data; }
}

2. 自定义业务异常 BusinessException.java

public class BusinessException extends RuntimeException{
    private Integer code;

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

    public Integer getCode() {
        return code;
    }
}

3. 全局异常处理器 GlobalExceptionHandler.java

import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@RestControllerAdvice
public class GlobalExceptionHandler {

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

    // 捕获参数校验异常
    @ExceptionHandler(BindException.class)
    public Result<?> handleValidException(BindException e){
        String msg = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(400, msg);
    }

    // 兜底捕获所有未知异常
    @ExceptionHandler(Exception.class)
    public Result<?> handleException(Exception e){
        e.printStackTrace();
        return Result.fail(500, "服务器内部错误,请稍后重试");
    }
}

4. 测试Controller UserController.java

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Min;

@RestController
@RequestMapping("/api/user")
@Validated
public class UserController {

    @GetMapping("/get")
    public Result<String> getUser(@RequestParam @Min(value = 1, message = "用户ID必须大于0") Integer id){
        if(id == 999){
            throw new BusinessException(4001, "用户不存在");
        }
        return Result.success("当前用户ID:"+id);
    }
}

核心代码讲解

  1. @RestControllerAdvice
    这个注解是全局异常的核心,它会拦截所有@RestController标注的控制器抛出的异常,相当于全局切面。搭配@ExceptionHandler指定要捕获的异常类型。
  2. 三层异常分类处理
  • BusinessException:业务主动抛出的异常,例如账号不存在、权限不足,可自定义错误码;
  • BindException:JSR303参数校验失败抛出,例如数字范围、非空校验不通过;
  • Exception:顶层兜底,捕获空指针、IO异常等未知系统错误,不直接返回堆栈信息,保护服务安全。
  1. 统一返回体
    所有正常响应和异常响应,返回的JSON结构完全一致,前端只需要一套解析逻辑,大幅降低前后端联调成本。

本地测试

启动SpringBoot应用,访问接口测试:

  1. [http://127.0.0.1:8080/api/user/get?id=-1](http://127.0.0.1:8080/api/user/get?id=-1)
    触发参数校验,返回提示:用户ID必须大于0
  2. [http://127.0.0.1:8080/api/user/get?id=999](http://127.0.0.1:8080/api/user/get?id=999)
    抛出自定义业务异常,返回错误码4001,提示用户不存在
  3. 制造空指针等其他错误,会统一返回500友好提示。

实战踩坑记录

  1. 注意@Validated注解:写在Controller类上,参数校验才会生效,很容易遗漏;
  2. 异常处理器无法捕获过滤器Filter中抛出的异常,Filter层面异常需要单独处理;
  3. 生产环境不要把原始异常堆栈返回前端,只在后端日志打印,防止信息泄露;
  4. 自定义异常不要继承Exception(受检异常),继承RuntimeException运行时异常,无需手动throws。

生产优化方向

  1. 完善错误码枚举类,统一管理项目全部业务错误码;
  2. 增加日志框架,异常发生时自动记录日志到文件;
  3. 增加对HttpRequestMethodNotSupportedException等web常见异常单独处理;
  4. 接入告警,当500服务异常大量触发时发送通知。

总结

全局异常处理是SpringBoot项目标准化开发的必备模块,几乎所有企业项目都会使用这套方案。它解决了接口返回格式混乱、重复try-catch、异常信息泄露等多个痛点。

本项目代码量简洁,没有复杂依赖,你可以打包部署到华为云ECS,通过Postman反复测试各类异常场景。掌握这个能力之后,后续开发SpringBoot业务项目都可以直接复用这套全局异常模板,提升开发效率。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。