SpringBoot实战:搭建简易全局异常处理器
【摘要】
在后端项目开发中,异常处理是保障接口稳定性、统一返回格式的关键。很多新手习惯在每个接口中写大量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);
}
}
核心代码讲解
- @RestControllerAdvice
这个注解是全局异常的核心,它会拦截所有@RestController标注的控制器抛出的异常,相当于全局切面。搭配@ExceptionHandler指定要捕获的异常类型。 - 三层异常分类处理
- BusinessException:业务主动抛出的异常,例如账号不存在、权限不足,可自定义错误码;
- BindException:JSR303参数校验失败抛出,例如数字范围、非空校验不通过;
- Exception:顶层兜底,捕获空指针、IO异常等未知系统错误,不直接返回堆栈信息,保护服务安全。
- 统一返回体
所有正常响应和异常响应,返回的JSON结构完全一致,前端只需要一套解析逻辑,大幅降低前后端联调成本。
本地测试
启动SpringBoot应用,访问接口测试:
[http://127.0.0.1:8080/api/user/get?id=-1](http://127.0.0.1:8080/api/user/get?id=-1)
触发参数校验,返回提示:用户ID必须大于0[http://127.0.0.1:8080/api/user/get?id=999](http://127.0.0.1:8080/api/user/get?id=999)
抛出自定义业务异常,返回错误码4001,提示用户不存在- 制造空指针等其他错误,会统一返回500友好提示。
实战踩坑记录
- 注意
@Validated注解:写在Controller类上,参数校验才会生效,很容易遗漏; - 异常处理器无法捕获过滤器Filter中抛出的异常,Filter层面异常需要单独处理;
- 生产环境不要把原始异常堆栈返回前端,只在后端日志打印,防止信息泄露;
- 自定义异常不要继承Exception(受检异常),继承RuntimeException运行时异常,无需手动throws。
生产优化方向
- 完善错误码枚举类,统一管理项目全部业务错误码;
- 增加日志框架,异常发生时自动记录日志到文件;
- 增加对HttpRequestMethodNotSupportedException等web常见异常单独处理;
- 接入告警,当500服务异常大量触发时发送通知。
总结
全局异常处理是SpringBoot项目标准化开发的必备模块,几乎所有企业项目都会使用这套方案。它解决了接口返回格式混乱、重复try-catch、异常信息泄露等多个痛点。
本项目代码量简洁,没有复杂依赖,你可以打包部署到华为云ECS,通过Postman反复测试各类异常场景。掌握这个能力之后,后续开发SpringBoot业务项目都可以直接复用这套全局异常模板,提升开发效率。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)