1359 字
约 4 分钟
1
Spring Boot 全局异常处理:统一管理你的 API 错误
Spring Boot 全局异常处理:统一管理你的 API 错误
在开发 Spring Boot 后端接口时,全局异常处理 是一个非常重要且实用的特性。它能帮助我们:
- 统一返回统一的错误格式
- 减少大量的重复
try-catch - 提升接口的安全性和健壮性
- 标准化错误提示,提高用户体验
为什么要使用全局异常处理?
1. 统一异常格式
不同业务场景下,异常抛出类型各不相同:
- 表单验证失败抛
MethodArgumentNotValidException - 空指针异常抛
NullPointerException - 自定义业务异常抛
CustomException
使用全局异常处理后,所有异常都会返回一致的 JSON 格式(如:{"code": 500, "message": "服务器内部错误"}),便于前端统一处理。
2. 减少重复代码
每次写接口都要手动处理异常,不仅麻烦,而且容易遗漏。全局异常处理可以集中管理所有异常,避免重复代码。
3. 统一错误提示
把错误码、错误信息、错误类型等统一封装,便于前端根据不同的 code 做不同的处理(如:跳转到 404 页面、显示友好的提示等)。
4. 提升接口安全性
全局异常处理可以捕获所有可能抛出的异常(如:空指针、SQL 异常、IO 异常等),避免敏感信息泄露到前端。
5. 标准化错误码管理
通过自定义错误枚举,可以对所有业务错误进行统一管理,便于查询和维护。
自定义异常类
1. 业务异常类(推荐使用)
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
private int code; // 自定义错误码
private String message; // 异常信息
private Object data; // 额外数据
// 构造方法重载
public BusinessException(int code, String message) {
super(message);
this.code = code;
this.message = message;
}
public BusinessException(int code, String message, Object data) {
super(message);
this.code = code;
this.message = message;
this.data = data;
}
public BusinessException(String message) {
super(message);
this.code = 500;
this.message = message;
}
// Getter + Setter
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public Object getData() {
return data;
}
}
2. 自定义错误枚举(推荐)
public enum ErrorCode {
// 通用错误
SUCCESS(200, "操作成功"),
FAILED(500, "操作失败"),
PARAM_ERROR(1001, "参数错误"),
UNAUTHORIZED(1002, "未授权"),
FORBIDDEN(1003, "禁止访问"),
NOT_FOUND(1004, "资源不存在"),
SYSTEM_ERROR(5000, "服务器内部错误"),
// 业务场景错误
USER_NOT_FOUND(2001, "用户不存在"),
PASSWORD_ERROR(2002, "密码错误"),
ACCOUNT_DISABLED(2003, "账号已被禁用"),
EMAIL_EXISTS(2004, "邮箱已被注册"),
PHONE_EXISTS(2005, "手机号已被注册"),
INVALID_TOKEN(2006, "无效的 Token"),
TOKEN_EXPIRED(2007, "Token 已过期"),
// 文件系统错误
FILE_NOT_FOUND(3001, "文件不存在");
private int code;
private String message;
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public static ErrorCode fromCode(int code) {
for (ErrorCode errorCode : ErrorCode.values()) {
if (errorCode.code == code) {
return errorCode;
}
}
return FAILED;
}
}
全局异常处理器
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
@RestControllerAdvice
public class GlobalExceptionHandler {
// 自定义业务异常
@ExceptionHandler(BusinessException.class)
public Result<Object> handleBusinessException(BusinessException ex) {
return Result.failure(ex.getCode(), ex.getMessage());
}
// 自定义错误枚举异常
@ExceptionHandler(IllegalArgumentException.class)
public Result<Object> handleIllegalArgumentException(IllegalArgumentException ex) {
ErrorCode errorCode = ErrorCode.fromCode(Integer.parseInt(ex.getMessage()));
return Result.failure(errorCode.getCode(), errorCode.getMessage());
}
// 表单验证异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
String message = bindingResult.getFieldError().getDefaultMessage();
return Result.failure(1001, message);
}
// 请求参数校验异常
@ExceptionHandler(BindException.class)
public Result<Object> handleBindException(BindException ex) {
String message = ex.getBindingResult().getFieldError().getDefaultMessage();
return Result.failure(1001, message);
}
// 空指针异常
@ExceptionHandler(NullPointerException.class)
public Result<Object> handleNullPointerException(NullPointerException ex) {
return Result.failure(5001, "空指针异常:" + ex.getMessage());
}
// 其他未知异常
@ExceptionHandler(Exception.class)
public Result<Object> handleException(Exception ex) {
return Result.failure(5000, "服务器内部错误:" + ex.getMessage());
}
// 自定义返回工具类
private static class Result<T> {
private int code;
private String message;
private T data;
private Result(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> Result<T> success() {
return new Result<>(200, "操作成功", null);
}
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
public static <T> Result<T> failure(int code, String message) {
return new Result<>(code, message, null);
}
}
}
最佳实践
- 使用自定义异常:抛出
BusinessException或IllegalArgumentException,便于统一处理。 - 统一错误码:通过
ErrorCode枚举统一管理所有错误码,便于维护和查询。 - 优先抛出运行时异常:如
RuntimeException、BusinessException等,避免强制捕获。 - 日志记录:在全局异常处理器中打印异常堆栈,便于排查问题。
- 扩展性强:支持多种异常类型,方便后续扩展。
总结
全局异常处理是 Spring Boot 开发中非常重要的一个特性。通过自定义异常类、自定义错误枚举、全局异常处理器,我们可以实现对所有 API 错误的统一管理和优雅处理。
掌握全局异常处理后,你的接口将更加健壮、安全,前端调用也更加方便。
相关内链推荐:
- Spring Boot 自定义响应工具类:为什么要用 + 实战指南
- Spring Boot JSR 380 参数校验实战:@NotNull、@Email、@Size 完整指南
- Spring Boot AOP 实现 API 请求日志切面(自定义注解实战)
SEO 优化建议:
- 标题包含核心关键词:“Spring Boot”、“全局异常处理”、“自定义异常”、“业务异常”。
- 建议添加更多代码截图,提升用户动手能力。
Spring Boot 全局异常处理:统一管理你的 API 错误
http://clxhxhhr.top/posts/330/ 评论
0 条
还没有评论,先写一条吧。