Validation

Spring MVC 具有针对`@RequestMapping`方法的内置validation,包括Java Bean Validation。验证可能应用于以下两个级别之一:

  1. @ModelAttribute,@RequestBody@RequestPart参数解析器会逐个验证方法参数,如果方法参数用 Jakarta @Valid`或 Spring 的 `@Validated,_AND_注释,紧随其后没有 Errors`或 `BindingResult`参数,则不需要方法验证(下文将讨论)。此情况下引发的异常为 `MethodArgumentNotValidException

  2. @Constraint`等注释(如 `@Min,@NotBlank`等)直接声明在方法参数上,或在方法上(对于返回值),则必须应用方法验证,且该验证会取代方法参数级别的验证,因为方法验证涵盖了方法参数约束和通过 `@Valid`进行的嵌套约束。此情况下引发的异常为 `HandlerMethodValidationException

应用程序必须处理 MethodArgumentNotValidExceptionHandlerMethodValidationException,因为根据控制器方法的签名可能会引发其中任一个异常。但这两个异常的设计非常相似,并且可以用几乎相同的代码来处理。主要区别在于前者适用于单个对象,而后者适用于方法参数列表。

@Valid 不是约束注释,而是对象中嵌套约束的注释。因此,@Valid 本身不会导致方法验证。另一方面,@NotNull 是一个约束,将它添加到 @Valid 参数会导致方法验证。对于可空性,还可以使用 @RequestBody@ModelAttributerequired 标志。

方法验证可以与`Errors`或`BindingResult`方法参数结合使用。但是,仅当所有验证错误紧跟在具有`Errors`的某个方法参数上时,才会调用控制器方法。如果其他任何方法参数上存在验证错误,则会抛出`HandlerMethodValidationException`。

您可以通过WebMvc config全局配置一个`Validator`,或通过`@Controller`或`@ControllerAdvice`中一个@InitBinder方法本地配置。您还可以使用多个验证器。

如果控制器具有类级别的 @Validated,则 method validation is applied 通过 AOP 代理。要利用 Spring 框架 6.1 中添加的 Spring MVC 内置方法验证支持,您需要从控制器中删除类级别的 @Validated 注释。

Error Responses部分提供了如何处理`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) {
			// ...
       }
})