验证

Spring MVC 内置了用于@RequestMapping 方法的验证,包括Java Bean 验证。验证可以在以下两个级别之一应用

  1. @ModelAttribute@RequestBody@RequestPart 参数解析器会分别验证方法参数,前提是方法参数用 Jakarta @Valid 或 Spring 的 @Validated 进行注释,并且紧随其后没有ErrorsBindingResult 参数,并且不需要方法验证(将在后面讨论)。在这种情况下引发的异常是MethodArgumentNotValidException

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

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

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

方法验证可以与ErrorsBindingResult 方法参数结合使用。但是,只有当所有验证错误都位于带有紧随其后的Errors 的方法参数上时,才会调用控制器方法。如果任何其他方法参数上存在验证错误,则会引发HandlerMethodValidationException

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

如果控制器具有类级别的@Validated,则通过 AOP 代理应用方法验证。为了利用 Spring 框架 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) {
			// ...
       }
})