導言
SpringBoot提供了一種開箱即用的異常處理機制。的默認實現。ErrorController在捕獲和處理異常方面做得很好。而且,我們仍然可以定義我們自己的@ExceptionHandlerS來捕獲和處理特定的異常。但是,仍有改進的餘地:
即使我們決定使用自定義來處理所有異常@ExceptionHandler,某些異常仍將設法轉義該處理程序和ErrorController將負責異常處理。這@ExceptionHandlerv.V.ErrorController二元性是絕對可以改善的。
有時,默認的錯誤表示看起來有點混亂:
{
"timestamp": "2018-09-23T15:05:32.681+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"NotBlank.dto.name",
"NotBlank.name",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"dto.name",
"name"
],
"arguments": null,
"defaultMessage": "name",
"code": "name"
}
],
"defaultMessage": "{name.not_blank}",
"objectName": "dto",
"field": "name",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotBlank"
}
],
"message": "Validation failed for object='dto'. Error count: 1",
"path": "/"
}
當然,我們可以通過註冊一個自定義來改進這一點。ErrorAttributes實現,但更明智和固執己見(仍然很容易定製)的默認表示將是最好的。
對於驗證錯誤,可以很容易地將約束中的一些參數公開給內插消息。例如,int值可以使用{}佔位符語法但是,其他例外情況並非如此:
public class UserAlreadyExistsException extends RuntimeException {
// How can I expose this value to the interpolated message?
private final String username;
// constructors and getters and setters
}
如果我們有內置的支持應用層錯誤碼所有例外。有時,只需使用適當的http狀態代碼,我們找不到到底出了什麼問題。例如,如果同一個端點上的兩個完全不同的錯誤具有相同的狀態代碼,怎麼辦?
有待改進的餘地
這個errors-spring-boot-starter提供一種Bootiful、一致和固執己見的方法來處理各種異常。基於SpringBoot的異常處理機制,errors-spring-boot-starter報盤:
1,處理所有異常的一致方法–不管是驗證/綁定錯誤還是自定義域特定的錯誤,甚至是與Spring相關的錯誤。所有這些都將由WebErrorHandler實現處理(不再有ErrorController VS@ExceptionHandler)
2,對應用程序特定錯誤代碼的內置支持,同樣適用於所有可能的錯誤.
3,使用MessageSource的簡單錯誤消息插值。
4,可自定義的HTTP錯誤表示形式。
5,公開從異常到錯誤消息的參數。
默認錯誤表示
默認情況下,錯誤將是具有以下模式的JSON結果:
// For each error, there is a code/messsge combination in the errors array
{
"errors": [
{
"code": "first_error_code",
"message": "1st error message"
}
]
}
爲了自定義此表示,只需註冊HttpErrorAttributesAdapter。
一致錯誤處理方法
所有異常將由WebErrorHandler執行。默認情況下,這個啓動程序會參考一些內置的內容。WebErrorHandler方法來處理下列特定異常:
1,處理所有驗證/綁定異常的實現。
2,類註釋的自定義異常的實現。@ExceptionMapping.
3,一個處理SpringMVC特定異常的實現。
4,如果SpringSecurity在類路徑上,則是一個處理SpringSecurity特定異常的實現。
通過實現WebErrorHandler實現.
內置錯誤代碼支持
雖然在RESTfulAPI中使用適當的HTTP狀態代碼是一種推薦的方法,但有時我們需要更多的信息來了解到底出了什麼問題。這裏是錯誤碼進來。您可以將錯誤代碼視爲機器可讀性錯誤描述。每個異常都可以映射到至少一個錯誤代碼。
這個異常到錯誤代碼映射根據異常類型而有所不同:
驗證錯誤代碼將從message 相應約束註釋的屬性,例如@NotBlank(message = “name.required”).
這個errorCode屬性爲帶註釋的異常。@ExceptionMapping如下所示:
@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {}
自定義實現的代碼WebErrorHandler :
public class ExistedUserHandler implements WebErrorHandler {
@Override
public boolean canHandle(Throwable exception) {
return exception instanceof UserAlreadyExistsException;
}
@Override
public HandledException handle(Throwable exception) {
return new HandledException("user.already_exists", BAD_REQUEST, null);
}
}
揭露論點
與SpringBoot一樣,您可以從約束註釋傳遞驗證參數。@Min(value = 18, message = “age.min”),到擬內插信息:
age.min = The minimum age is {0}!
此外,爲了支持驗證錯誤的此特性,我們使用@ExposeAsArg 註釋例如,如果我們要在以下消息中指定已經使用的用戶名:
user.already_exists=Another user with the '{0}' username already exists
你可以寫:
@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {
@ExposeAsArg(0) private final String username;
// constructor
}