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 {@Overridepublic Map<String, Object> getErrorAttributes(...) {Map<String, Object> map = super.getErrorAttributes(...);map.put("traceId", UUID.randomUUID().toString()); // 添加追蹤IDreturn 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 # 錯誤屬性擴展