在 Spring Boot 應用開發中,統一的異常處理機制不僅能提升代碼可維護性,更能確保 API 回應格式一致性。本文將由淺入深,詳細解析 Spring Boot 中三種異常處理層級的實現方式、優先級規則及最佳實踐。
當只需針對特定 Controller 處理異常時,可直接在該類別中使用 @ExceptionHandler 註解。
@RestController
@RequestMapping("/advice1")
@Api("測試 ControllerAdvice 與全域異常處理")
public class AdviceController {
@GetMapping("/test1")
public String test1() {
throw new RuntimeException("advice1 - exception1");
}
@GetMapping("/test2")
public String test2() {
throw new RuntimeException("advice1 - exception2");
}
@ExceptionHandler(RuntimeException.class)
public MyExceptionResponse exceptionHandler() {
MyExceptionResponse resp = new MyExceptionResponse();
resp.setCode(300);
resp.setMsg("exception-Handler");
return resp;
}
}
關鍵點:
@ExceptionHandler 指定需處理的異常類型(支援多種異常類別)@RestController,需額外加上 @ResponseBody@ControllerAdvice 是 Spring MVC 提供的切面增強類別,最常見用途即為全域異常處理。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public MyExceptionResponse exceptionHandler(RuntimeException e, HttpServletResponse response) {
MyExceptionResponse resp = new MyExceptionResponse();
resp.setCode(300);
resp.setMsg("全域異常處理: " + e.getMessage());
// response.setStatus(600); // 可自訂 HTTP 狀態碼
return resp;
}
}
透過註解屬性可精確控制掃描範圍:
@ControllerAdvice(annotations = RestController.class):僅掃描標註 @RestController 的類別@ControllerAdvice(basePackages = {"com.xxx", "com.ooo"}):指定基礎包路徑@ControllerAdvice(assignableTypes = {MyController.class}):指定具體類別| 回傳類型 | 說明 | 需搭配註解 |
|---|---|---|
| String | 視為視圖名稱,進行頁面跳轉 | 無 |
| ModelAndView | 攜帶模型與視圖資訊 | 無 |
| 自定義物件 | 序列化為 JSON 回應 | @ResponseBody (或類別標註 @RestController) |
當同一異常被多層處理器覆蓋時,Spring 遵循「範圍越小優先級越高」的原則:
@ExceptionHandler > 類別層級 @ExceptionHandler@ExceptionHandler > @ControllerAdvice 全域處理器MyRuntimeException 優先於 RuntimeException)實戰建議: 在
@ControllerAdvice中定義通用異常處理(如參數驗證失敗、資源不存在、系統錯誤),在特定 Controller 中僅處理該業務特有的異常情況。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {
private int code;
private String message;
private T data;
private long timestamp = System.currentTimeMillis();
}
// 業務異常:預期內的錯誤(如庫存不足、參數錯誤)
public class BusinessException extends RuntimeException {
private final int code;
public BusinessException(int code, String msg) { super(msg); this.code = code; }
}
// 系統異常:不可預期的錯誤(如資料庫連線失敗、第三方服務超時)
@ExceptionHandler(Exception.class)
@ResponseBody
public ApiResponse<Void> handleSystemError(Exception e, HttpServletRequest request) {
log.error("系統異常: {}", request.getRequestURI(), e);
return new ApiResponse<>(500, "系統內部錯誤", null);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ApiResponse<Map<String, String>> handleValidationError(MethodArgumentNotValidException e) {
Map<String, String> errors = new HashMap<>();
e.getBindingResult().getFieldErrors().forEach(err ->
errors.put(err.getField(), err.getDefaultMessage()));
return new ApiResponse<>(400, "參數驗證失敗", errors);
}
掌握 Spring Boot 異常處理機制,能讓你的應用在面對錯誤時更優雅、更可控。建議在專案初期即建立完善的異常處理體系,包含統一響應格式、異常分類、日誌記錄與監控告警,為系統穩定性奠定基礎。