Spring Framework 提供了对 Java Bean 验证 API 的支持。spring-doc.cn

Bean 验证概述

Bean Validation 提供了一种通用的验证方法,通过 constraint declaration 和 元数据。要使用它,您可以使用 声明性验证约束,然后由运行时强制执行。有 built-in constraints,您还可以定义自己的自定义 constraints。spring-doc.cn

请考虑以下示例,该示例显示了一个具有两个属性的简单模型:PersonFormspring-doc.cn

public class PersonForm {
	private String name;
	private int age;
}
class PersonForm(
		private val name: String,
		private val age: Int
)

Bean 验证允许您声明约束,如下例所示:spring-doc.cn

public class PersonForm {

	@NotNull
	@Size(max=64)
	private String name;

	@Min(0)
	private int age;
}
class PersonForm(
	@get:NotNull @get:Size(max=64)
	private val name: String,
	@get:Min(0)
	private val age: Int
)

然后,Bean 验证器根据声明的 约束。有关 API 的 API 创建。请参阅 Hibernate Validator 文档 特定约束。了解如何将 Bean 验证提供程序设置为 Spring Bean,请继续阅读。spring-doc.cn

配置 Bean 验证提供程序

Spring 提供了对 Bean 验证 API 的全面支持,包括 Bean Validation 提供程序作为 Spring Bean。这允许您注入 or anywhere 验证 在您的应用程序中需要。jakarta.validation.ValidatorFactoryjakarta.validation.Validatorspring-doc.cn

你可以使用 将默认的 Validator 配置为 Spring bean,如下例所示:LocalValidatorFactoryBeanspring-doc.cn

import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class AppConfig {

	@Bean
	public LocalValidatorFactoryBean validator() {
		return new LocalValidatorFactoryBean();
	}
}
<bean id="validator"
	class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

前面示例中的基本配置触发 bean 验证以通过以下方式初始化 使用其默认的引导机制。Bean Validation 提供程序,例如 Hibernate Validator 应存在于 Classpath 中,并被自动检测。spring-doc.cn

注入 Jakarta Validator

LocalValidatorFactoryBean同时实现 AND ,因此你可以注入对后者的引用 apply 验证逻辑(如果您更喜欢直接使用 Bean 验证 API), 如下例所示:jakarta.validation.ValidatorFactoryjakarta.validation.Validatorspring-doc.cn

import jakarta.validation.Validator;

@Service
public class MyService {

	@Autowired
	private Validator validator;
}
import jakarta.validation.Validator;

@Service
class MyService(@Autowired private val validator: Validator)

注入 Spring 验证器

除了实现 之外,还会适应 ,因此你可以注入一个引用 如果 bean 需要 Spring Validation API,则将其更改为后者。jakarta.validation.ValidatorLocalValidatorFactoryBeanorg.springframework.validation.Validatorspring-doc.cn

例如:spring-doc.cn

import org.springframework.validation.Validator;

@Service
public class MyService {

	@Autowired
	private Validator validator;
}
import org.springframework.validation.Validator

@Service
class MyService(@Autowired private val validator: Validator)

当用作 时,调用底层 ,然后将 s 改编为 s,并将它们注册到对象中 传递到方法中。org.springframework.validation.ValidatorLocalValidatorFactoryBeanjakarta.validation.ValidatorContraintViolationFieldErrorErrorsvalidatespring-doc.cn

配置自定义约束

每个 bean 验证约束由两部分组成:spring-doc.cn

  • 声明约束及其可配置属性的注释。@Constraintspring-doc.cn

  • 实现 约束的行为。jakarta.validation.ConstraintValidatorspring-doc.cn

为了将声明与实现相关联,每个注解 引用相应的实现类。在运行时,当 约束注释。@ConstraintConstraintValidatorConstraintValidatorFactoryspring-doc.cn

默认情况下,配置使用 Spring 创建实例。这使您的自定义可以像任何其他 Spring bean 一样从依赖关系注入中受益。LocalValidatorFactoryBeanSpringConstraintValidatorFactoryConstraintValidatorConstraintValidatorsspring-doc.cn

以下示例显示了一个自定义声明,后跟一个使用 Spring 进行依赖项注入的关联实现:@ConstraintConstraintValidatorspring-doc.cn

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator::class)
annotation class MyConstraint
import jakarta.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

	@Autowired;
	private Foo aDependency;

	// ...
}
import jakarta.validation.ConstraintValidator

class MyConstraintValidator(private val aDependency: Foo) : ConstraintValidator {

	// ...
}

如前面的示例所示,实现可以像任何其他 Spring bean 一样具有其依赖项。ConstraintValidator@Autowiredspring-doc.cn

Spring 驱动的方法验证

您可以将 Bean Validation 的方法验证功能集成到 Spring 上下文:MethodValidationPostProcessorspring-doc.cn

import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@Configuration
public class AppConfig {

	@Bean
	public static MethodValidationPostProcessor validationPostProcessor() {
		return new MethodValidationPostProcessor();
	}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>

要获得 Spring 驱动的方法验证的资格,需要对目标类进行注释 替换为 Spring 的注解,它也可以选择性地声明验证 要使用的组。参见MethodValidationPostProcessor来获得 Hibernate Validator 和 Bean Validation 提供程序的设置细节。@Validatedspring-doc.cn

方法验证依赖于 AOP 代理 目标类,可以是接口上方法的 JDK 动态代理或 CGLIB 代理。 使用代理存在某些限制,其中一些限制在 了解 AOP 代理 中进行了介绍。此外,请记住 始终在代理类上使用方法和访问器;直接字段访问将不起作用。spring-doc.cn

Spring MVC 和 WebFlux 内置了对相同底层方法验证的支持,但没有 对 AOP 的需求。因此,请检查本节的其余部分,并参阅 Spring MVC 验证错误响应部分,以及 WebFlux 验证错误响应部分。spring-doc.cn

方法验证异常

默认情况下,使用 返回的 s 集引发。作为替代方案, 你可以用 S 来代替 Raise 适应错误。要启用,请设置以下标志:jakarta.validation.ConstraintViolationExceptionConstraintViolationjakarta.validation.ValidatorMethodValidationExceptionConstraintViolationMessageSourceResolvablespring-doc.cn

import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@Configuration
public class AppConfig {

	@Bean
	public static MethodValidationPostProcessor validationPostProcessor() {
		MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
		processor.setAdaptConstraintViolations(true);
		return processor;
	}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
	<property name="adaptConstraintViolations" value="true"/>
</bean>

MethodValidationException包含一个 s 列表,其中 按方法参数对错误进行分组,每个错误都会公开一个 、 参数 值,以及改编自 s 的错误列表。对于级联冲突开启的方法参数 fields 和 properties 中,是 which 将验证错误实现并公开为 S。ParameterValidationResultMethodParameterMessageSourceResolvableConstraintViolation@ValidParameterValidationResultParameterErrorsorg.springframework.validation.ErrorsFieldErrorspring-doc.cn

自定义验证错误

调整后的错误可以转换为错误消息,以 通过配置的区域设置和特定于语言的 资源包。本节提供了一个示例进行说明。MessageSourceResolvableMessageSourcespring-doc.cn

给定以下类声明:spring-doc.cn

record Person(@Size(min = 1, max = 10) String name) {
}

@Validated
public class MyService {

	void addStudent(@Valid Person person, @Max(2) int degrees) {
		// ...
	}
}
@JvmRecord
internal data class Person(@Size(min = 1, max = 10) val name: String)

@Validated
class MyService {

	fun addStudent(person: @Valid Person?, degrees: @Max(2) Int) {
		// ...
	}
}

a on 改编为 a ,如下所示:ConstraintViolationPerson.name()FieldErrorspring-doc.cn

  • 错误代码 、 、 和"Size.person.name""Size.name""Size.java.lang.String""Size"spring-doc.cn

  • 消息参数 、 和 (字段名称和 constraint 属性)"name"101spring-doc.cn

  • 默认消息 “size must be between 1 and 10”spring-doc.cn

要自定义默认消息,您可以使用上述任何错误代码和消息参数将属性添加到 MessageSource 资源包中。另请注意, message 参数本身是一个带有错误代码的 AND 也可以自定义。例如:"name"MessagreSourceResolvable"person.name""name"spring-doc.cn

性能
Size.person.name=Please, provide a {0} that is between {2} and {1} characters long
person.name=username

a 对 method 参数进行以下调整为 a:ConstraintViolationdegreesMessageSourceResolvablespring-doc.cn

  • 错误代码 、 、 、"Max.myService#addStudent.degrees""Max.degrees""Max.int""Max"spring-doc.cn

  • 消息参数 “degrees2 和 2 (字段名称和 constraint 属性)spring-doc.cn

  • 默认消息 “must be less than or equal to 2”spring-doc.cn

要自定义上述默认消息,您可以添加如下属性:spring-doc.cn

性能
Max.degrees=You cannot provide more than {1} {0}

其他配置选项

默认配置足以满足大多数 例。各种 Bean 验证有许多配置选项 构造,从消息插值到遍历解析。有关这些选项的更多信息,请参见LocalValidatorFactoryBean javadoc。LocalValidatorFactoryBeanspring-doc.cn

方法验证依赖于 AOP 代理 目标类,可以是接口上方法的 JDK 动态代理或 CGLIB 代理。 使用代理存在某些限制,其中一些限制在 了解 AOP 代理 中进行了介绍。此外,请记住 始终在代理类上使用方法和访问器;直接字段访问将不起作用。spring-doc.cn

配置DataBinder

您可以使用 .配置完成后,您可以 通过调用 来调用 。任何验证都是 自动添加到 Binder 的 .DataBinderValidatorValidatorbinder.validate()ErrorsBindingResultspring-doc.cn

以下示例演示如何以编程方式使用 a 调用验证 绑定到目标对象后的逻辑:DataBinderspring-doc.cn

Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());

// bind to the target object
binder.bind(propertyValues);

// validate the target object
binder.validate();

// get BindingResult that includes any validation errors
BindingResult results = binder.getBindingResult();
val target = Foo()
val binder = DataBinder(target)
binder.validator = FooValidator()

// bind to the target object
binder.bind(propertyValues)

// validate the target object
binder.validate()

// get BindingResult that includes any validation errors
val results = binder.bindingResult

您还可以通过 和 配置具有多个实例的 。这在以下情况下很有用 将全局配置的 bean 验证与配置的 Spring 相结合 本地的 DataBinder 实例。参见 Spring MVC 验证配置DataBinderValidatordataBinder.addValidatorsdataBinder.replaceValidatorsValidatorspring-doc.cn

Spring MVC 3 验证

参见 Spring MVC 一章中的 验证spring-doc.cn