Java Bean Validation
LocalValidatorFactoryBean, Validator, Constraint, ConstraintValidator, SpringConstraintValidatorFactory, Method Validation, MethodValidationPostProcessor :description: Spring Framework 提供对 Bean Validation API 的支持,该 API 提供了一个通用方法来验证 Java 应用程序中的数据。通过使用约束注释声明验证约束并由运行时强制执行,Bean Validation 允许开发人员实施复杂的验证规则。Spring 集成了 Bean Validation,允许将验证器注入应用程序中需要验证的任何位置,并且可以通过注入 Validator 或 ValidatorFactory 接口直接使用 Bean Validation API。此外,Spring 提供了 LocalValidatorFactoryBean,它将 Bean 验证提供程序自举为 Spring bean,并允许自定义约束验证器实现和方法验证特性。
Spring Framework 提供对https://beanvalidation.org[Java Bean Validation] API 的支持。
The Spring Framework provides support for the Java Bean Validation API.
Overview of Bean Validation
Bean Validation 通过约束声明和元数据为 Java 应用程序提供了一个通用的验证方法。要使用它,需要用声明验证约束注释域模型属性,然后由运行时强制执行。有内置约束,也可以定义自己的自定义约束。
Bean Validation provides a common way of validation through constraint declaration and metadata for Java applications. To use it, you annotate domain model properties with declarative validation constraints which are then enforced by the runtime. There are built-in constraints, and you can also define your own custom constraints.
考虑以下示例,它显示了一个带有两个属性的简单 PersonForm
模型:
Consider the following example, which shows a simple PersonForm
model with two properties:
-
Java
-
Kotlin
public class PersonForm {
private String name;
private int age;
}
class PersonForm(
private val name: String,
private val age: Int
)
Bean 验证允许你声明约束,如下例所示:
Bean Validation lets you declare constraints as the following example shows:
-
Java
-
Kotlin
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 的一般信息,请参阅 Bean 验证。有关特定约束,请参阅 Hibernate Validator 文档。要了解如何将 Bean 验证提供程序设置为 Spring Bean,请继续阅读。
A Bean Validation validator then validates instances of this class based on the declared constraints. See Bean Validation for general information about the API. See the Hibernate Validator documentation for specific constraints. To learn how to set up a bean validation provider as a Spring bean, keep reading.
Configuring a Bean Validation Provider
Spring 完全支持 Bean Validation API,包括将 Bean 验证提供程序自举为 Spring bean。这允许你在应用程序中需要验证的任何地方注入 jakarta.validation.ValidatorFactory
或 jakarta.validation.Validator
。
Spring provides full support for the Bean Validation API including the bootstrapping of a
Bean Validation provider as a Spring bean. This lets you inject a
jakarta.validation.ValidatorFactory
or jakarta.validation.Validator
wherever validation
is needed in your application.
可以使用 LocalValidatorFactoryBean
将默认验证器配置为 Spring bean,如下例所示:
You can use the LocalValidatorFactoryBean
to configure a default Validator as a Spring
bean, as the following example shows:
-
Java
-
XML
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 验证提供程序(例如 Hibernate Validator)会在类路径中,并且会自动检测到它们。
The basic configuration in the preceding example triggers bean validation to initialize by using its default bootstrap mechanism. A Bean Validation provider, such as the Hibernate Validator, is expected to be present in the classpath and is automatically detected.
Inject Jakarta Validator
LocalValidatorFactoryBean
同时实现了 jakarta.validation.ValidatorFactory
和 jakarta.validation.Validator
,所以你可以注入后者的引用以应用验证逻辑(如果你更愿意直接使用 Bean Validation API),如下例所示:
LocalValidatorFactoryBean
implements both jakarta.validation.ValidatorFactory
and
jakarta.validation.Validator
, so you can inject a reference to the latter to
apply validation logic if you prefer to work with the Bean Validation API directly,
as the following example shows:
-
Java
-
Kotlin
import jakarta.validation.Validator;
@Service
public class MyService {
@Autowired
private Validator validator;
}
import jakarta.validation.Validator;
@Service
class MyService(@Autowired private val validator: Validator)
Inject Spring Validator
除了实现 jakarta.validation.Validator
之外,LocalValidatorFactoryBean
还适应于 org.springframework.validation.Validator
,所以如果 bean 要求使用 Spring Validation API,你就可以注入后者的引用。
In addition to implementing jakarta.validation.Validator
, LocalValidatorFactoryBean
also adapts to org.springframework.validation.Validator
, so you can inject a reference
to the latter if your bean requires the Spring Validation API.
例如:
For example:
-
Java
-
Kotlin
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)
当用作 org.springframework.validation.Validator
时,LocalValidatorFactoryBean
调用底层的 jakarta.validation.Validator
,然后将 ContraintViolation
适应为 FieldError
,并用它们向传递给 validate
方法的 Errors
对象注册。
When used as org.springframework.validation.Validator
, LocalValidatorFactoryBean
invokes the underlying jakarta.validation.Validator
, and then adapts
ContraintViolation`s to `FieldError`s, and registers them with the `Errors
object
passed into the validate
method.
Configure Custom Constraints
每个 bean 验证约束包含两部分:
Each bean validation constraint consists of two parts:
-
A
@Constraint
annotation that declares the constraint and its configurable properties. -
An implementation of the
jakarta.validation.ConstraintValidator
interface that implements the constraint’s behavior.
为了将声明与实现关联起来,每个 @Constraint
注解引用对应的 ConstraintValidator
实现类。在运行时,当约束注解在你的领域模型中被使用时,ConstraintValidatorFactory
实例化引用的实现。
To associate a declaration with an implementation, each @Constraint
annotation
references a corresponding ConstraintValidator
implementation class. At runtime, a
ConstraintValidatorFactory
instantiates the referenced implementation when the
constraint annotation is encountered in your domain model.
默认情况下,LocalValidatorFactoryBean
配置一个 SpringConstraintValidatorFactory
,它使用 Spring 来创建 ConstraintValidator
实例。这样,自定义的 ConstraintValidators
像其他 Spring bean 一样可以从依赖注入中受益。
By default, the LocalValidatorFactoryBean
configures a SpringConstraintValidatorFactory
that uses Spring to create ConstraintValidator
instances. This lets your custom
ConstraintValidators
benefit from dependency injection like any other Spring bean.
以下示例展示了一个自定义 @Constraint
声明,后面是一个相关的 ConstraintValidator
实现,它使用 Spring 进行依赖注入:
The following example shows a custom @Constraint
declaration followed by an associated
ConstraintValidator
implementation that uses Spring for dependency injection:
-
Java
-
Kotlin
@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
-
Java
-
Kotlin
import jakarta.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
@Autowired;
private Foo aDependency;
// ...
}
import jakarta.validation.ConstraintValidator
class MyConstraintValidator(private val aDependency: Foo) : ConstraintValidator {
// ...
}
如前例所示,ConstraintValidator
实现可以像其他 Spring bean 一样对其依赖项 @Autowired
。
As the preceding example shows, a ConstraintValidator
implementation can have its dependencies
@Autowired
as any other Spring bean.
Spring-driven Method Validation
你可以通过 MethodValidationPostProcessor
bean 定义将 Bean Validation 的方法验证特性集成到 Spring 上下文中:
You can integrate the method validation feature of Bean Validation into a
Spring context through a MethodValidationPostProcessor
bean definition:
-
Java
-
Kotlin
-
Xml
@Configuration
public class ApplicationConfiguration {
@Bean
public static MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
@Configuration
class ApplicationConfiguration {
companion object {
@Bean
@JvmStatic
fun validationPostProcessor() = MethodValidationPostProcessor()
}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
为了符合 Spring 驱动的验证验证方法,目标类需要使用 Spring 的 @Validated`注释,该注释可以选择还声明要使用的验证组。请参阅https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.html[`MethodValidationPostProcessor
],以了解使用 Hibernate Validator 和 Bean Validation 提供程序时的设置详情。
To be eligible for Spring-driven method validation, target classes need to be annotated
with Spring’s @Validated
annotation, which can optionally also declare the validation
groups to use. See
MethodValidationPostProcessor
for setup details with the Hibernate Validator and Bean Validation providers.
方法验证依赖于目标类周围的 AOP Proxies,或者 JDK 动态代理(用于接口方法)或 CGLIB 代理。使用代理存在一定的局限性,其中一些在 Understanding AOP Proxies 中进行了描述。此外,请务必始终对代理类使用的方法和访问器;直接字段访问将不起作用。 Method validation relies on AOP Proxies around the target classes, either JDK dynamic proxies for methods on interfaces or CGLIB proxies. There are certain limitations with the use of proxies, some of which are described in Understanding AOP Proxies. In addition remember to always use methods and accessors on proxied classes; direct field access will not work. |
Spring MVC 和 WebFlux 内置对相同底层方法验证的支持,但无需 AOP。因此,请查看本节的其余部分,并了解 Spring MVCValidation和Error Responses部分,以及 WebFluxValidation和Error Responses部分。
Spring MVC and WebFlux have built-in support for the same underlying method validation but without the need for AOP. Therefore, do check the rest of this section, and also see the Spring MVC Validation and Error Responses sections, and the WebFlux Validation and Error Responses sections.
Method Validation Exceptions
默认情况下,jakarta.validation.ConstraintViolationException
由 jakarta.validation.Validator
返回的 ConstraintViolation
集合引发。作为替代,你可以改为引发 MethodValidationException
,其中 ConstraintViolation
适应了 MessageSourceResolvable
错误。要启用,请设置以下标志:
By default, jakarta.validation.ConstraintViolationException
is raised with the set of
ConstraintViolation`s returned by `jakarta.validation.Validator
. As an alternative,
you can have MethodValidationException
raised instead with ConstraintViolation`s
adapted to `MessageSourceResolvable
errors. To enable set the following flag:
-
Java
-
Kotlin
-
Xml
@Configuration
public class ApplicationConfiguration {
@Bean
public static MethodValidationPostProcessor validationPostProcessor() {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setAdaptConstraintViolations(true);
return processor;
}
}
@Configuration
class ApplicationConfiguration {
companion object {
@Bean
@JvmStatic
fun validationPostProcessor() = MethodValidationPostProcessor().apply {
setAdaptConstraintViolations(true)
}
}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
<property name="adaptConstraintViolations" value="true"/>
</bean>
MethodValidationException
包含一个 ParameterValidationResult
列表,该列表按方法参数对错误进行分组,每个错误都公开一个 MethodParameter
、参数值以及一个从 ConstraintViolation
转换而来的 MessageSourceResolvable
错误列表。对于在字段和属性上具有级联违规的 @Valid
方法参数,ParameterValidationResult
是 ParameterErrors
,它实现了 org.springframework.validation.Errors
并将验证错误作为 FieldError
公开。
MethodValidationException
contains a list of ParameterValidationResult`s which
group errors by method parameter, and each exposes a `MethodParameter
, the argument
value, and a list of MessageSourceResolvable
errors adapted from
ConstraintViolation`s. For `@Valid
method parameters with cascaded violations on
fields and properties, the ParameterValidationResult
is ParameterErrors
which
implements org.springframework.validation.Errors
and exposes validation errors as
`FieldError`s.
Customizing Validation Errors
适配的 MessageSourceResolvable
错误可以转换成错误消息,通过配置的 MessageSource
使用特定于区域设置和语言的资源包显示给用户。本节提供了一个例子来说明这一点。
The adapted MessageSourceResolvable
errors can be turned into error messages to
display to users through the configured MessageSource
with locale and language specific
resource bundles. This section provides an example for illustration.
给定以下类声明:
Given the following class declarations:
-
Java
-
Kotlin
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) {
// ...
}
}
Person.name()
上的 ConstraintViolation
适应了带有以下内容的 FieldError
:
A ConstraintViolation
on Person.name()
is adapted to a FieldError
with the following:
-
Error codes
"Size.student.name"
,"Size.name"
,"Size.java.lang.String"
, and"Size"
-
Message arguments
"name"
,10
, and1
(the field name and the constraint attributes) -
Default message "size must be between 1 and 10"
要自定义默认消息,则可以使用上述错误代码和消息参数将属性添加到 MessageSource 资源捆绑包中。另请注意,消息参数 "name"
本身是带有错误代码 "student.name"
和 "name"
的 MessageSourceResolvable
,也可以自定义。例如:
To customize the default message, you can add properties to
MessageSource
resource bundles using any of the above errors codes and message arguments. Note also that the
message argument "name"
is itself a MessageSourceResolvable
with error codes
"student.name"
and "name"
and can customized too. For example:
- Properties
-
Size.student.name=Please, provide a {0} that is between {2} and {1} characters long student.name=username
degrees
方法参数上的 ConstraintViolation
适应了带有以下内容的 MessageSourceResolvable
:
A ConstraintViolation
on the degrees
method parameter is adapted to a
MessageSourceResolvable
with the following:
-
Error codes
"Max.myService#addStudent.degrees"
,"Max.degrees"
,"Max.int"
,"Max"
-
Message arguments "degrees2 and 2 (the field name and the constraint attribute)
-
Default message "must be less than or equal to 2"
要自定义上述默认消息,你可以添加这样的属性:
To customize the above default message, you can add a property such as:
- Properties
-
Max.degrees=You cannot provide more than {1} {0}
Additional Configuration Options
默认的`LocalValidatorFactoryBean`配置对于大多数情况来说已经足够了。对于各种 Bean 验证构造,有许多配置选项,从消息内插到遍历解决。有关这些选项的更多信息,请参见https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation//beanvalidation/LocalValidatorFactoryBean.html[LocalValidatorFactoryBean
] javadoc。
The default LocalValidatorFactoryBean
configuration suffices for most
cases. There are a number of configuration options for various Bean Validation
constructs, from message interpolation to traversal resolution. See the
LocalValidatorFactoryBean
javadoc for more information on these options.
Configuring a DataBinder
你可以使用 Validator
配置一个 DataBinder
实例。配置完毕后,你可以通过调用 binder.validate()
来调用 Validator
。所有验证 Errors
会自动添加到 binder 的 BindingResult
中。
You can configure a DataBinder
instance with a Validator
. Once configured, you can
invoke the Validator
by calling binder.validate()
. Any validation Errors
are
automatically added to the binder’s BindingResult
.
以下示例展示了如何在绑定到目标对象后以编程方式使用 DataBinder
来调用验证逻辑:
The following example shows how to use a DataBinder
programmatically to invoke validation
logic after binding to a target object:
-
Java
-
Kotlin
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
您还可以通过`dataBinder.addValidators`和`dataBinder.replaceValidators`使用多个`Validator`实例配置一个`DataBinder`。当将全局配置的 bean 验证与 Spring `Validator`在 DataBinder 实例上局部配置的 bean 验证相结合时,这非常有用。见Spring MVC Validation Configuration。
You can also configure a DataBinder
with multiple Validator
instances through
dataBinder.addValidators
and dataBinder.replaceValidators
. This is useful when
combining globally configured bean validation with a Spring Validator
configured
locally on a DataBinder instance. See
Spring MVC Validation Configuration.
Spring MVC 3 Validation
请参阅 Spring MVC 章节中的Validation。
See Validation in the Spring MVC chapter.