Spring Boot 提供了多种灵活的方式实现异常处理,以下是核心方案和最佳实践:
一、基础异常处理方案
1. @ControllerAdvice
+ @ExceptionHandler
(全局处理)
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理特定异常(如业务异常)
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
ErrorResponse error = new ErrorResponse(ex.getCode(), ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
// 处理所有未捕获异常
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
ErrorResponse error = new ErrorResponse("500", "服务器内部错误");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 自定义错误响应体
@Data
class ErrorResponse {
private String code;
private String message;
// 可扩展时间戳、路径等字段
}
作用:
- 捕获控制器层抛出的所有异常,返回结构化错误信息
- 支持区分异常类型定制HTTP状态码和响应体
2. @ResponseStatus
(简单场景)
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "资源不存在")
public class ResourceNotFoundException extends RuntimeException {
// 自动返回404状态码和指定消息
}
二、REST API 增强处理
1. 自定义错误数据结构
{
"timestamp": "2025-06-22T10:00:00",
"status": 404,
"error": "Not Found",
"path": "/api/users/999"
}
通过继承 DefaultErrorAttributes
可扩展字段:
@Component
public class CustomErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(...) {
Map<String, Object> map = super.getErrorAttributes(...);
map.put("traceId", UUID.randomUUID().toString()); // 添加追踪ID
return map;
}
}
2. OpenAPI/Swagger 集成
在 @ControllerAdvice
中补充注解:
@Operation(responses = {
@ApiResponse(responseCode = "400", description = "业务参数错误"),
@ApiResponse(responseCode = "500", description = "系统内部错误")
})
三、特殊场景处理
1. 校验异常处理(Validation)
自动捕获 MethodArgumentNotValidException
:
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(MethodArgumentNotValidException ex) {
String errorMsg = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return new ResponseEntity<>(new ErrorResponse("400", errorMsg), HttpStatus.BAD_REQUEST);
}
2. Servlet 容器级错误
配置 ErrorController
处理404等底层错误:
@RestController
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public ResponseEntity<ErrorResponse> handleError(HttpServletRequest request) {
Integer status = (Integer) request.getAttribute("javax.servlet.error.status_code");
return new ResponseEntity<>(new ErrorResponse(status.toString(), "请求路径不存在"), HttpStatus.valueOf(status));
}
}
四、最佳实践建议
分层处理
- 业务层抛出自定义异常(如
OrderNotFoundException
) - 控制器层专注参数校验和流程控制
- 全局处理器统一转换异常为响应
- 业务层抛出自定义异常(如
日志记录
在@ExceptionHandler
中记录错误堆栈:@ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex, HttpServletRequest request) { log.error("Request {} failed: {}", request.getRequestURI(), ex.getMessage(), ex); // ...返回响应 }
前端友好
返回标准化错误码(如1001=用户不存在
),便于前端识别处理。
五、完整项目结构示例
src/main/java/
├── exception/
│ ├── GlobalExceptionHandler.java # 全局处理器
│ ├── BusinessException.java # 自定义业务异常
│ └── ErrorResponse.java # 错误响应体
└── config/
└── CustomErrorAttributes.java # 错误属性扩展