Java Bean Validation
TODAY Framework 提供了对 Java Bean Validation API 的支持。
Bean Validation 概述
Bean Validation 通过约束声明和元数据为 Java 应用程序提供了一种通用的验证方式。要使用它,您可以用声明性验证约束来注释域模型属性,然后由运行时强制执行这些约束。有一些内置约束,您也可以定义自己的自定义约束。
考虑以下示例,它显示了一个具有两个属性的简单 PersonForm 模型:
-
Java
public class PersonForm {
private String name;
private int age;
}
Bean Validation 允许您声明约束,如下例所示:
-
Java
public class PersonForm {
@NotNull
@Size(max=64)
private String name;
@Min(0)
private int age;
}
然后,Bean Validation 验证器根据声明的约束验证此类的实例。有关 API 的一般信息,请参阅 Bean Validation。有关特定约束,请参阅 Hibernate Validator 文档。要了解如何将 bean 验证提供者设置为 Infra bean,请继续阅读。
配置 Bean Validation 提供者
Infra 为 Bean Validation API 提供全面支持,包括将 Bean Validation 提供者引导为 Infra bean。这使您可以在应用程序中需要验证的任何地方注入 jakarta.validation.ValidatorFactory 或 jakarta.validation.Validator。
您可以使用 LocalValidatorFactoryBean 将默认验证器配置为 Infra bean,如下例所示:
-
Java
-
XML
import infra.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class AppConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
<bean id="validator" class="infra.validation.beanvalidation.LocalValidatorFactoryBean"/>
前面示例中的基本配置触发 bean 验证使用其默认引导机制进行初始化。Bean Validation 提供者(如 Hibernate Validator)应存在于类路径中并被自动检测到。
注入 Jakarta Validator
LocalValidatorFactoryBean 同时实现了 jakarta.validation.ValidatorFactory 和 jakarta.validation.Validator,因此如果您更喜欢直接使用 Bean Validation API,您可以注入对后者的引用来应用验证逻辑,如下例所示:
-
Java
import jakarta.validation.Validator;
@Service
public class MyService {
@Autowired
private Validator validator;
}
注入 Infra Validator
除了实现 jakarta.validation.Validator 之外,LocalValidatorFactoryBean 还适配了 infra.validation.Validator,因此如果您的 bean 需要 Infra Validation API,您可以注入对后者的引用。
例如:
-
Java
import infra.validation.Validator;
@Service
public class MyService {
@Autowired
private Validator validator;
}
当用作 infra.validation.Validator 时,LocalValidatorFactoryBean 会调用底层的 jakarta.validation.Validator,然后将 ContraintViolation 适配为 FieldError,并将它们注册到传递给 validate 方法的 Errors 对象中。
配置自定义约束
每个 bean 验证约束由两部分组成:
-
一个
@Constraint注解,声明约束及其可配置属性。 -
一个
jakarta.validation.ConstraintValidator接口的实现,实现约束的行为。
为了将声明与实现相关联,每个 @Constraint 注解都引用一个相应的 ConstraintValidator 实现类。在运行时,当在您的域模型中遇到约束注解时,ConstraintValidatorFactory 会实例化引用的实现。
默认情况下,LocalValidatorFactoryBean 配置一个 InfraConstraintValidatorFactory,它使用 Infra 来创建 ConstraintValidator 实例。这使您的自定义 ConstraintValidator 可以像任何其他 Infra bean 一样受益于依赖注入。
以下示例显示了一个自定义 @Constraint 声明,后跟一个关联的 ConstraintValidator 实现,该实现使用 Infra 进行依赖注入:
-
Java
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
-
Java
import jakarta.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
@Autowired;
private Foo aDependency;
// ...
}
如前面的示例所示,ConstraintValidator 实现可以像任何其他 Infra bean 一样将其依赖项 @Autowired。
Infra 驱动的方法验证
您可以通过 MethodValidationPostProcessor bean 定义将 Bean Validation 的方法验证功能集成到 Infra 上下文中:
-
Java
-
XML
import infra.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
<bean class="infra.validation.beanvalidation.MethodValidationPostProcessor"/>
要有资格进行 Infra 驱动的方法验证,目标类需要使用 Infra @Validated 注解进行注释,该注解还可以选择声明要使用的验证组。有关使用 Hibernate Validator 和 Bean Validation 提供者的设置详细信息,请参阅 MethodValidationPostProcessor。
方法验证异常
默认情况下,使用 jakarata.validation.Validator 返回的 ConstraintViolation 集合引发 jakarta.validation.ConstraintViolationException。作为替代方案,您可以引发 MethodValidationException,并将 ConstraintViolation 适配为 MessageSourceResolvable 错误。要启用,请设置以下标志:
-
Java
-
XML
import infra.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setAdaptConstraintViolations(true);
return processor;
}
}
<bean class="infra.validation.beanvalidation.MethodValidationPostProcessor">
<property name="adaptConstraintViolations" value="true"/>
</bean>
MethodValidationException 包含一个 ParameterValidationResult 列表,该列表按方法参数对错误进行分组,每个结果公开一个 MethodParameter、参数值以及从 ConstraintViolation 适配而来的 MessageSourceResolvable 错误列表。对于在字段和属性上具有级联违规的 @Valid 方法参数,ParameterValidationResult 是 ParameterErrors,它实现了 infra.validation.Errors 并将验证错误公开为 FieldError。
自定义验证错误
适配后的 MessageSourceResolvable 错误可以通过配置的 MessageSource 转换为错误消息,以显示给用户,并支持特定于区域和语言的资源包。本节提供了一个示例进行说明。
给定以下类声明:
-
Java
record Person(@Size(min = 1, max = 10) String name) {
}
@Validated
public class MyService {
void addStudent(@Valid Person person, @Max(2) int degrees) {
// ...
}
}
Person.name() 上的 ConstraintViolation 适配为具有以下内容的 FieldError:
-
错误代码
"Size.student.name"、"Size.name"、"Size.java.lang.String"和"Size" -
消息参数
"name"、10和1(字段名称和约束属性) -
默认消息 "size must be between 1 and 10"
要自定义默认消息,您可以使用上述任何错误代码和消息参数向 MessageSource 资源包添加属性。另请注意,消息参数 "name" 本身是一个 MessagreSourceResolvable,其错误代码为 "student.name" 和 "name",也可以自定义。例如:
- Properties
-
Size.student.name=Please, provide a {0} that is between {2} and {1} characters long student.name=username
degrees 方法参数上的 ConstraintViolation 适配为具有以下内容的 MessageSourceResolvable:
-
错误代码
"Max.myService#addStudent.degrees"、"Max.degrees"、"Max.int"、"Max" -
消息参数 "degrees" 和 2(字段名称和约束属性)
-
默认消息 "must be less than or equal to 2"
要自定义上述默认消息,您可以添加如下属性:
- Properties
-
Max.degrees=You cannot provide more than {1} {0}
其他配置选项
默认的 LocalValidatorFactoryBean 配置足以满足大多数情况。对于各种 Bean Validation 构造,从消息插值到遍历解析,有许多配置选项。有关这些选项的更多信息,请参阅 LocalValidatorFactoryBean javadoc。
配置 DataBinder
您可以使用 Validator 配置 DataBinder 实例。配置完成后,您可以通过调用 binder.validate() 来调用 Validator。任何验证 Errors 都会自动添加到绑定器的 BindingResult 中。
以下示例显示了如何以编程方式使用 DataBinder 在绑定到目标对象后调用验证逻辑:
-
Java
Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());
// 绑定到目标对象
binder.bind(propertyValues);
// 验证目标对象
binder.validate();
// 获取包含任何验证错误的 BindingResult
BindingResult results = binder.getBindingResult();
您还可以通过 dataBinder.addValidators 和 dataBinder.replaceValidators 为 DataBinder 配置多个 Validator 实例。当将全局配置的 bean 验证与在 DataBinder 实例上本地配置的 Infra Validator 结合使用时,这非常有用。请参阅 Web MVC 验证配置。
Web MVC 验证
请参阅 Web MVC 章节中的 验证。