一句话总结
Spring Boot 统一异常处理核心:@ControllerAdvice + @ExceptionHandler 全局拦截异常,配合 统一响应体 Result<T>(code + message + data)返回规范格式。处理层级:自定义业务异常 → 参数校验异常 → 系统异常兜底。关键点:@ExceptionHandler 优先级(子类异常优先匹配)、@ResponseBody 自动转 JSON、@Validated 校验异常统一处理。
初级理解
统一响应体
# 统一响应体封装
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
private int code; // 状态码
private String message; // 提示信息
private T data; // 数据
public static <T> Result<T> success(T data) {
return new Result<>(200, "success", data);
}
public static <T> Result<T> error(int code, String message) {
return new Result<>(code, message, null);
}
}
# Controller 使用
@RestController
public class UserController {
@GetMapping("/user/{id}")
public Result<User> getUser(@PathVariable Long id) {
User user = userService.getById(id);
return Result.success(user);
}
}
# 返回 JSON
# {"code":200,"message":"success","data":{"id":1,"name":"张三"}}
中级深入
全局异常处理
# @ControllerAdvice 全局异常处理
@RestControllerAdvice // = @ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {
// 1. 处理自定义业务异常
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
// 2. 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValidationException(MethodArgumentNotValidException e) {
String message = e.getBindingResult()
.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.error(400, message);
}
// 3. 兜底处理未知异常
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
log.error("系统异常", e);
return Result.error(500, "系统繁忙,请稍后重试");
}
}
自定义业务异常
# 自定义异常类
public class BusinessException extends RuntimeException {
private int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public BusinessException(String message) {
this(400, message);
}
}
# 使用
@Service
public class UserService {
public User getById(Long id) {
User user = userDao.selectById(id);
if (user == null) {
throw new BusinessException(404, "用户不存在");
}
return user;
}
}
高级拓展
@ExceptionHandler 匹配规则
# 异常匹配优先级
# 1. 精确匹配:抛出的异常类型 == @ExceptionHandler 声明的类型
# 2. 子类匹配:抛出子类异常,匹配父类处理器
# 3. 最接近匹配:多个处理器都匹配时,选继承链最近的
# 示例
@ExceptionHandler(RuntimeException.class)
public Result handleRuntime() { } // 处理器 A
@ExceptionHandler(IllegalArgumentException.class)
public Result handleIllegal() { } // 处理器 B
# 抛出 IllegalArgumentException → 匹配 B(更精确)
# 抛出 NullPointerException → 匹配 A(只有 A 能匹配)
参数校验统一处理
# DTO 参数校验
@Data
public class UserDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 18, message = "年龄不能小于18")
@Max(value = 100, message = "年龄不能大于100")
private int age;
}
# Controller
@PostMapping("/user")
public Result<Void> createUser(@Valid @RequestBody UserDTO dto) {
userService.create(dto);
return Result.success(null);
}
# 校验失败时抛出 MethodArgumentNotValidException
# 由 GlobalExceptionHandler 统一处理
实战场景
场景:完整统一返回方案
# 1. 定义错误码枚举
public enum ErrorCode {
SUCCESS(200, "成功"),
BAD_REQUEST(400, "参数错误"),
UNAUTHORIZED(401, "未登录"),
FORBIDDEN(403, "无权限"),
NOT_FOUND(404, "资源不存在"),
SERVER_ERROR(500, "服务器错误");
private int code;
private String message;
}
# 2. 统一响应体
@Data
public class Result<T> {
private int code;
private String message;
private T data;
private long timestamp = System.currentTimeMillis();
public static <T> Result<T> success(T data) {
Result<T> r = new Result<>();
r.code = ErrorCode.SUCCESS.getCode();
r.message = ErrorCode.SUCCESS.getMessage();
r.data = data;
return r;
}
public static <T> Result<T> error(ErrorCode errorCode) {
Result<T> r = new Result<>();
r.code = errorCode.getCode();
r.message = errorCode.getMessage();
return r;
}
}
面试模拟
面试官:Spring Boot 如何做统一异常处理?
你:使用 @RestControllerAdvice + @ExceptionHandler。定义 GlobalExceptionHandler 类,用 @ExceptionHandler 分别处理业务异常、参数校验异常、系统异常。配合统一响应体 Result,返回规范的 JSON 格式。
面试官:@ControllerAdvice 和 @ExceptionHandler 的原理?
你:@ControllerAdvice 本质是 AOP,它会被注册为全局的 Controller 增强。当 Controller 抛出异常时,DispatcherServlet 会查找匹配的 @ExceptionHandler 方法,按异常类型精确匹配,找到后调用并返回结果。