文章目錄
Spring提供多種方法將異常轉化爲響應:
- 特定的Spring異常會自動映射爲指定的HTTP狀態碼;
- 異常上可以添加
@ResponseStatus
註解,從而將其映射爲某一個狀態碼; - 在方法上可以添加
ExceptionHandler
註解,使其用來處理異常;
將異常映射爲HTTP狀態碼
Spring異常自動映射
Spring異常 | HTTP狀態碼 |
---|---|
BindException | 400-Bad Request |
ConversionNotSupportedException | 500-Internal Error |
HttpMediaTypeNotAcceptableException | 406-Not Acceptable |
HttpMediaTypeNotSupportedException | 415-Unsupported Media Type |
HttpMessageNotReadableException | 400-Bad Request |
HttpMessageNotWritableException | 500-Internal Server Error |
HttpRequestMethodNotSupportedException | 405-Method Not Allow |
MethodArgumentNotValidException | 400-Bad Request |
MissingServletRequestParameterException | 400-Bad Request |
MissingServletRequestPartException | 400-Bad Request |
NoSuchRequestHandlingMethodException | 404-Not Found |
TypeMismatchException | 400-Bad Request |
上述異常由Spring自身拋出,作爲DispatcherServlet處理過程中或執行校驗時出現問題的結果。
@ResponseStatus
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "service not found")
public class MyException extends RuntimeException{
}
@RestController
public class ExceptionController {
@GetMapping("exception")
private void exceptionTest(@RequestParam String param){
if("no".equals(param)){
throw new MyException();
}
}
}
上述代碼中使用@ResponseStatus
註解,在程序拋出MyException時,指定響應具有404狀態碼。
@ExceptionHandler
處理異常希望響應中不僅包含狀態碼,還需要包含產生的錯誤,僅將異常映射爲HTTP狀態碼就不夠了。此時,需要按照處理請求的方式來處理異常。
@PostMapping("exception/handler")
public String exceptionHandler(@Nullable FileMode fileMode){
try {
fileMode.getName().toLowerCase();
} catch (Exception e) {
return "false";
}
return fileMode.getName();
}
上述代碼中,異常處理代碼和業務邏輯代碼混在了一起。我們可以利用@ExceptionHandler
將異常處理邏輯抽取出來。
@PostMapping("exception/handler")
public String exceptionHandler(@Nullable FileMode fileMode){
fileMode.getName().toLowerCase();
return fileMode.getName();
}
@ExceptionHandler(Exception.class)
public String handlerException(){
return "false";
}
將業務邏輯和異常處理分開,代碼結構更加清晰。
⚠️:@ExceptionHandler標註的方法可以處理同一個控制器中
所有的處理器方法拋出的異常;若要處理所有控制器方法拋出的異常,需要將@ExceptionHandler標註的方法定義到控制器通知類
中。
爲控制器添加通知(@ControllerAdvice)
控制器通知類使用@ControllerAdvice
標註,會包含一個或多個如下類型方法:
- @ExceptionHandler註解標註的方法:
全局處理控制器中異常。 - @InitBinder註解標註的方法:
設置WebDataBinder,用來自動綁定前臺請求參數到Model中。 - @ModelAttribute註解標註的方法:
綁定鍵值對到Model裏,此處是讓全局的@RequestMapping都能獲取在此處設置的鍵值對。
在通知類中,上述方法會運用到所有controller中帶有@RequestMapping的方法上。
@ControllerAdvice本身帶有@Component。
使用樣例如下,很好地體現了通知類中各個註解的作用:
@ControllerAdvice
public class GlobleControllerAdvice {
//@ExceptionHandler參數中指定處理的異常或在方法參數中指定
@ExceptionHandler(Exception.class)
public ModelAndView exceptionHandler(Exception e, WebRequest request){
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("errorMessage", e.getMessage());
return modelAndView;
}
/**
* 在執行控制器之前執行,初始化數據模型,鍵值對可以用ModelMap接收
* @param model
*/
@ModelAttribute
public void addAttribute(Model model){
model.addAttribute("globleModelAttr", "gma");
}
/**
* 控制器參數轉換之前被執行的代碼
* @param webDataBinder Spring MVC會自動生成的參數
*/
@InitBinder
public void initBinder(WebDataBinder webDataBinder){
//自定義日期編輯器
CustomDateEditor dateEditor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false);
webDataBinder.registerCustomEditor(Date.class, dateEditor);
}
}
上述代碼爲一個ControllerAdvice示例,調用代碼如下:
@RestController
public class ExceptionController {
@GetMapping("/exception")
public ModelAndView testExceptionHandler(Date date, ModelMap modelMap){
System.out.println(modelMap.get("globleModelAttr"));
System.out.println(date);
throw new NullPointerException("yanzy test error message");
}
}
錯誤頁面定義:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>錯誤頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<!-- jquery -->
<script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
</head>
<body>
<h1 th:text="*{errorMessage}"></h1>
<h1 th:text="*{globleModelAttr}"></h1>
</body>
</html>
請求此服務,僅帶有參數"?date=2019-05-08",響應結果爲:
<!DOCTYPE HTML>
<html>
<head>
<title>錯誤頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<!-- jquery -->
<script type="text/javascript" src="/js/jquery.min.js"></script>
</head>
<body>
<h1>yanzy test error message</h1>
<h1></h1>
</body>
</html>
控制檯打印信息:
gma
Wed May 08 00:00:00 CST 2019
多個@ExceptionHandler共存時優先級
根據聲明的異常匹配度進行優先級排序。
註解註釋的方法可以包含下列參數:
返回值可以爲下列類型:
⚠️:advice中的@ExceptionHandler優先級低於當前Controller中定義的@ExceptionHandler