驗證
Spring MVC 為 @RequestMapping 方法(包括 Java Bean Validation)提供了內建的驗證。驗證可以在兩個級別之一應用:
-
Java Bean Validation 單獨應用於透過
@jakarta.validation.Valid或 Spring 的@Validated註解的 @ModelAttribute、@RequestBody 和 @RequestPart 方法引數,只要它是一個命令物件而不是Map或Collection等容器,並且在方法簽名中緊隨其後沒有Errors或BindingResult,並且不以其他方式需要方法驗證(參見下一段)。當單獨驗證方法引數時,會丟擲MethodArgumentNotValidException異常。 -
當
@Constraint註解(如@Min、@NotBlank等)直接在方法引數上宣告,或為返回值在方法上宣告時,Java Bean Validation 將應用於該方法。它會取代任何原本將單獨應用於方法引數的驗證,因為方法驗證涵蓋了方法引數約束和透過@Valid的巢狀約束。當驗證應用於方法時,會丟擲HandlerMethodValidationException異常。
應用程式應處理 MethodArgumentNotValidException 和 HandlerMethodValidationException,因為根據控制器方法的簽名,兩者都可能被丟擲。然而,這兩個異常設計得非常相似,並且可以用幾乎相同的程式碼來處理。主要區別在於前者針對單個物件,而後者針對方法引數列表。
@Valid 不是一個約束註解,而是用於物件內部的巢狀約束。因此,單獨使用 @Valid 不會導致方法驗證。另一方面,@NotNull 是一個約束,將其新增到 @Valid 引數會導致方法驗證。對於空值檢查,您也可以使用 @RequestBody 或 @ModelAttribute 的 required 標誌。 |
方法驗證可以與 Errors 或 BindingResult 方法引數結合使用。但是,只有當所有驗證錯誤都發生在緊隨其後帶有 Errors 的方法引數上時,才會呼叫控制器方法。如果任何其他方法引數存在驗證錯誤,則會丟擲 HandlerMethodValidationException。
您可以透過 WebMvc 配置全域性配置 Validator,或透過 @Controller 或 @ControllerAdvice 中的 @InitBinder 方法區域性配置。您也可以使用多個驗證器。
如果控制器具有類級別的 @Validated,則 方法驗證將透過 AOP 代理應用。為了利用 Spring Framework 6.1 中新增的 Spring MVC 內建方法驗證支援,您需要從控制器中刪除類級別的 @Validated 註解。 |
錯誤響應部分提供了關於 MethodArgumentNotValidException 和 HandlerMethodValidationException 如何處理的更多詳細資訊,以及如何透過 MessageSource 和特定於區域設定和語言的資源包來自定義它們的呈現。
為了進一步自定義處理方法驗證錯誤,您可以擴充套件 ResponseEntityExceptionHandler 或在控制器或 @ControllerAdvice 中使用 @ExceptionHandler 方法,並直接處理 HandlerMethodValidationException。該異常包含一個 ParameterValidationResult 列表,該列表按方法引數分組驗證錯誤。您可以遍歷這些錯誤,或提供一個帶有控制器方法引數型別回撥方法的訪問者。
-
Java
-
Kotlin
HandlerMethodValidationException ex = ... ;
ex.visitResults(new HandlerMethodValidationException.Visitor() {
@Override
public void requestHeader(RequestHeader requestHeader, ParameterValidationResult result) {
// ...
}
@Override
public void requestParam(@Nullable RequestParam requestParam, ParameterValidationResult result) {
// ...
}
@Override
public void modelAttribute(@Nullable ModelAttribute modelAttribute, ParameterErrors errors) {
// ...
@Override
public void other(ParameterValidationResult result) {
// ...
}
});
// HandlerMethodValidationException
val ex
ex.visitResults(object : HandlerMethodValidationException.Visitor {
override fun requestHeader(requestHeader: RequestHeader, result: ParameterValidationResult) {
// ...
}
override fun requestParam(requestParam: RequestParam?, result: ParameterValidationResult) {
// ...
}
override fun modelAttribute(modelAttribute: ModelAttribute?, errors: ParameterErrors) {
// ...
}
// ...
override fun other(result: ParameterValidationResult) {
// ...
}
})