Spring Boot 全局异常处理:@ControllerAdvice 实战
统一的异常处理是 REST API 的基本要求。本文介绍 Spring Boot 全局异常处理的实现。
为什么需要全局异常处理?
- 统一响应格式:所有错误返回相同格式
- 集中管理:异常处理逻辑集中在一个地方
- 安全性:避免泄露内部错误信息
@ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusiness(BusinessException e) {
return ResponseEntity.status(e.getCode())
.body(new ErrorResponse(e.getCode(), e.getMessage()));
}
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldErrors().stream()
.map(err -> err.getField() + ": " + err.getDefaultMessage())
.collect(Collectors.joining(", "));
return ResponseEntity.badRequest()
.body(new ErrorResponse(400, message));
}
// 处理未找到异常
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException e) {
return ResponseEntity.status(404)
.body(new ErrorResponse(404, e.getMessage()));
}
// 处理所有其他异常
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception e) {
return ResponseEntity.status(500)
.body(new ErrorResponse(500, "服务器内部错误"));
}
}
自定义业务异常
public class BusinessException extends RuntimeException {
private final int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public BusinessException(String message) {
this(400, message);
}
public int getCode() { return code; }
}
统一响应格式
public class ApiResponse<T> {
private int code;
private String message;
private T data;
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(200, "success", data);
}
public static ApiResponse<?> error(int code, String message) {
return new ApiResponse<>(code, message, null);
}
}
使用示例
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public ApiResponse<User> findById(@PathVariable Long id) {
User user = userService.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
return ApiResponse.success(user);
}
@PostMapping
public ApiResponse<User> create(@Valid @RequestBody UserDTO dto) {
User user = userService.create(dto);
return ApiResponse.success(user);
}
}
最佳实践
- 分层处理:业务异常、参数异常、系统异常分别处理
- 统一格式:所有响应使用相同格式
- 日志记录:记录异常日志,方便排查
- 安全考虑:不要泄露内部错误信息
总结
全局异常处理是 REST API 的基本要求。通过 @ControllerAdvice 和 @ExceptionHandler,可以实现统一的异常处理。