Spring MVC 中,優雅處理異常的六種方式!
異常處理是每個 Java程序員需要面對的一個問題,在Spring中,提供了多種機制來處理控制器拋出的異常,確保應用程序在面對各種錯誤情況時能夠優雅地響應。這篇文章,我們來詳細分析Spring MVC中,幾種優雅處理異常的方式。
1. 使用@ExceptionHandler注解
@ExceptionHandler注解允許在單個Controller中定義處理特定異常的方法。當 Controller的方法拋出指定的異常時,Spring會調用相應的處理方法。
如下示例,展示了如何在 Controller層優雅處理異常:
@Controller
public class MyController {
@RequestMapping("/example")
public String example() {
// 可能拋出異常的業務邏輯
if (1/0) {
throw new CustomException("自定義異常發生");
}
return "success";
}
@ExceptionHandler(CustomException.class)
public ModelAndView handleCustomException(CustomException ex) {
ModelAndView mav = new ModelAndView();
mav.addObject("message", ex.getMessage());
mav.setViewName("errorPage");
return mav;
}
}
優點: 簡單直觀,適用于單個控制器的異常處理。
缺點: 如果多個控制器需要相同的異常處理邏輯,需要在每個控制器中重復定義。
2. 使用@ControllerAdvice注解
@ControllerAdvice是一種全局的異常處理方式,可以應用于所有 Controller。通過將異常處理邏輯集中在一個地方,可以避免代碼重復,提高維護性。
如下示例,展示了如何使用@ControllerAdvice優雅處理全局異常:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public ModelAndView handleCustomException(CustomException ex) {
ModelAndView mav = new ModelAndView();
mav.addObject("message", ex.getMessage());
mav.setViewName("errorPage");
return mav;
}
@ExceptionHandler(Exception.class)
public ModelAndView handleGeneralException(Exception ex) {
ModelAndView mav = new ModelAndView();
mav.addObject("message", "發生了一個錯誤: " + ex.getMessage());
mav.setViewName("errorPage");
return mav;
}
}
優點:
- 全局統一管理異常處理邏輯。
- 代碼更清晰,易于維護。
缺點:
- 全局處理不適用于需要針對某些控制器有特殊處理需求的情況,需結合其他方法使用。
3. 實現HandlerExceptionResolver接口
HandlerExceptionResolver 是一種更底層的異常處理機制,通過實現該接口,開發者可以自定義異常解析邏輯。
如下示例,展示了如何實現HandlerExceptionResolver接口優雅處理異常:
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
ModelAndView mav = new ModelAndView();
if (ex instanceof CustomException) {
mav.addObject("message", ex.getMessage());
mav.setViewName("customErrorPage");
} else {
mav.addObject("message", "未知錯誤");
mav.setViewName("errorPage");
}
return mav;
}
}
配置:
在 Spring 配置文件中注冊自定義異常解析器:
<bean class="com.example.MyExceptionResolver"/>
優點:
- 高度靈活,可以處理各種復雜的異常情景。
缺點:
- 需要更多的配置和實現工作。
- 不如注解方式直觀,適用性較低。
4. 使用@ResponseStatus注解
@ResponseStatus注解可以用于自定義異常對應的 HTTP 狀態碼和錯誤信息,當拋出帶有該注解的異常時,Spring會自動設置相應的狀態碼。
如下示例,展示了如何使用@ResponseStatus注解優雅處理異常:
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "資源未找到")
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
使用:
@Controller
public class MyController {
@RequestMapping("/resource")
public String getResource() {
// 假設資源未找到
throw new ResourceNotFoundException("資源ID不存在");
}
}
優點:簡單快捷,適用于直接映射到特定 HTTP 狀態碼的異常情況。
缺點:無法返回自定義的錯誤頁面或更復雜的錯誤信息。
5. 使用ResponseEntity和@RestControllerAdvice
在構建 RESTful API時,常用ResponseEntity來返回自定義的錯誤響應,并結合@RestControllerAdvice可以全局處理異常并返回 JSON 格式的錯誤信息。
如下示例,展示了如何使用ResponseEntity和@RestControllerAdvice來處理 RESTful API的異常:
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResponse> handleCustomException(CustomException ex) {
ErrorResponse error = new ErrorResponse("CUSTOM_ERROR", ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
ErrorResponse error = new ErrorResponse("GENERAL_ERROR", "內部服務器錯誤");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
public class ErrorResponse {
private String errorCode;
private String errorMessage;
// 構造方法、getter 和 setter
}
優點:
- 適用于 RESTful 服務,能夠返回結構化的錯誤信息(如 JSON)。
- 全局統一管理,易于維護。
缺點:
- 需要定義額外的錯誤響應類。
6. 使用@ControllerAdvice和@ExceptionHandler
如果使用 Spring Boot,可以更便捷地使用 @ControllerAdvice 結合自動配置實現異常處理。
如下示例,展示了如何使用@ControllerAdvice和@ExceptionHandler來處理異常:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationErrorResponse> handleValidationExceptions(
MethodArgumentNotValidException ex) {
ValidationErrorResponse errors = new ValidationErrorResponse();
ex.getBindingResult().getAllErrors().forEach((error) -> {
errors.addError(((FieldError) error).getField(), error.getDefaultMessage());
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
// 其它異常處理方法
}
優點:
- 與 Spring Boot 無縫集成,減少配置。
- 提供了諸多便利的功能,如自動處理驗證錯誤等。
總結
本文,我們分析了 Spring MVC優雅處理異常的幾種方法以及代碼示例,我們可以根據具體需求選擇合適的方法:
- 局部控制器處理:使用 @ExceptionHandler 注解,適用于單個控制器的特定異常處理。
- 全局處理:使用 @ControllerAdvice 或 @RestControllerAdvice,適用于跨多個控制器的統一異常處理。
- 自定義解析:實現 HandlerExceptionResolver 接口,適用于需要高度自定義的異常處理邏輯。
- 狀態碼注解:使用 @ResponseStatus 注解,適用于簡單的異常狀態碼映射。
- RESTful API:結合 ResponseEntity 和全局異常處理,返回結構化的錯誤響應。
從實際工作來看,@ControllerAdvice 或 @RestControllerAdvice是使用頻率最高的一種方式。