驗證

Spring MVC 為 @RequestMapping 方法提供了內建的驗證支援,包括Java Bean Validation。驗證可以在兩個級別中的一個應用:

  1. @ModelAttribute@RequestBody@RequestPart 引數解析器會單獨驗證方法引數,前提是方法引數帶有 Jakarta 的 @Valid 或 Spring 的 @Validated 註解,並且後面沒有緊跟著 ErrorsBindingResult 引數,並且不需要方法驗證(接下來討論)。在這種情況下丟擲的異常是 MethodArgumentNotValidException

  2. @Constraint 註解(例如 @Min@NotBlank 等)直接宣告在方法引數上,或者方法上(用於返回值),則必須應用方法驗證。這會取代方法引數級別的驗證,因為方法驗證涵蓋了方法引數約束和透過 @Valid 實現的巢狀約束。在這種情況下丟擲的異常是 HandlerMethodValidationException

應用程式必須處理 MethodArgumentNotValidExceptionHandlerMethodValidationException,因為根據控制器方法簽名,兩者都可能被丟擲。然而,這兩種異常的設計非常相似,可以使用幾乎相同的程式碼來處理。主要區別在於前者是針對單個物件,而後者是針對一組方法引數。

@Valid 不是一個約束註解,而是用於物件內的巢狀約束。因此,@Valid 本身不會導致方法驗證。另一方面,@NotNull 是一個約束,將其新增到 @Valid 引數會導致方法驗證。對於空性(nullability)而言,您也可以使用 @RequestBody@ModelAttributerequired 標誌。

方法驗證可以與 ErrorsBindingResult 方法引數結合使用。然而,只有當所有驗證錯誤都發生在緊隨其後帶有 Errors 引數的方法引數上時,控制器方法才會被呼叫。如果其他任何方法引數上存在驗證錯誤,則會丟擲 HandlerMethodValidationException

您可以透過WebMvc 配置全域性配置 Validator,或者透過 @Controller@ControllerAdvice 中的 @InitBinder 方法進行區域性配置。您也可以使用多個驗證器。

如果一個控制器有類級別的 @Validated 註解,那麼方法驗證會透過 AOP 代理應用。為了利用 Spring Framework 6.1 中新增的 Spring MVC 內建方法驗證支援,您需要從控制器中移除類級別的 @Validated 註解。

錯誤響應一節提供了關於如何處理 MethodArgumentNotValidExceptionHandlerMethodValidationException 的更多細節,以及如何透過 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) {
		// ...
	}
})