对于多属性验证,应使用类级别的约束。摘自 Bean Validation Sneak Peek第二部分:自定义约束:
类级别的约束
你们中有些人对应用跨越多个属性的约束或表达依赖于多个属性的约束的能力表示担忧。经典示例是地址验证。地址具有复杂的规则:
- 街道名称在某种程度上是标准名称,并且一定要有长度限制
- 邮政编码结构完全取决于国家/地区
- 该城市通常可以与邮政编码相关联,并且可以进行一些错误检查(前提是可以使用验证服务)
- 由于这些相互依赖关系,一个简单的属性级别约束确实可以满足要求
- Bean验证规范提供的解决方案有两个方面:
- 它提供了通过使用组和组序列来强制在另一组约束之前应用一组约束的功能。下一个博客条目将涵盖该主题
- 它允许定义类级别的约束
类级别约束是规则约束(注释/实现二重奏),适用于类而不是属性。换句话说,类级别的约束在中接收对象实例(而不是属性值)isValid。
```
@AddressAnnotation
public class Address {
@NotNull @Max(50) private String street1;
@Max(50) private String street2;
@Max(10) @NotNull private String zipCode;
@Max(20) @NotNull String city;
@NotNull private Country country;
...
}
@Constraint(validatedBy = MultiCountryAddressValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AddressAnnotation {
String message() default “{error.address}”;
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
public class MultiCountryAddressValidator implements ConstraintValidator {
public void initialize(AddressAnnotation constraintAnnotation) {
// initialize the zippre/city/country correlation service
}
public boolean isValid(Address object, ConstraintValidatorContext context) { if (!(object instanceof Address)) { throw new IllegalArgumentException("@Address only applies to Address"); } Address address = (Address) object; Country country = address.getCountry(); if (country.getISO2() == "FR") { // check address.getZipCode() structure for France (5 numbers) // check zippre and city correlation (calling an external service?) return isValid; } else if (country.getISO2() == "GR") { // check address.getZipCode() structure for Greece // no zippre / city correlation available at the moment return isValid; } // ...``` }
}
高级地址验证规则已被排除在地址对象之外,并由实现 MultiCountryAddressValidator。通过访问对象实例,类级别的约束具有很大的灵活性,并且可以验证多个相关属性。请注意,这里的排序不包括方程式,我们将在下一篇文章中再次讨论。
专家组讨论了多种属性支持方法:与其他涉及依赖的属性级别方法相比,我们认为类级别约束方法既提供了足够的简便性又提供了灵活性。欢迎您提供反馈。



