我如何validation两个或多个字段的组合?
我正在使用JPA 2.0 / Hibernatevalidation来validation我的模型。 我现在有一个情况需要validation两个字段的组合:
public class MyModel { public Integer getValue1() { //... } public String getValue2() { //... } }
如果getValue1()
和getValue2()
都为null
,则该模型无效 ,否则为有效。
我如何使用JPA 2.0 / Hibernate执行这种validation? 用一个简单的@NotNull
注解,两个getter必须是非空的才能通过validation。
对于多个属性validation,您应该使用类级约束。 从Beanvalidation偷看Peek第二部分:自定义约束 :
类级约束
你们中的一些人已经expression了关于跨越多个属性应用约束的能力或者expression依赖于多个属性的约束的能力。 经典的例子是地址validation。 地址有复杂的规则:
- 一个街道名称是有点标准的,必须有一定的长度限制
- 邮政编码结构完全取决于国家
- 这个城市通常可以与一个邮政编码相关联,并且可以进行一些错误检查(假设validation服务可以访问)
- 由于这些相互依存关系,简单的财产水平约束确实适合账单
Beanvalidation规范提供的解决scheme有两个:
- 它提供了通过使用组和组序列来强制一组约束在另一组约束之前被应用的能力。 这个主题将在下一篇博客文章中介绍
- 它允许定义类级约束
类级约束是适用于类而不是属性的常规约束(注释/实现二重奏)。 换言之,类级约束接收
isValid
的对象实例(而不是属性值)。@Address 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 Address { String message() default "{error.address}"; String[] groups() default {}; } public class MultiCountryAddressValidator implements ConstraintValidator<Address> { public void initialize(Address constraintAnnotation) { // initialize the zipcode/city/country correlation service } /** * Validate zipcode and city depending on the country */ public boolean isValid(Object object) { 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 zipcode and city correlation (calling an external service?) return isValid; } else if (country.getISO2() == "GR") { // check address.getZipCode() structure for Greece // no zipcode / city correlation available at the moment return isValid; } // ... } }
高级地址validation规则已被省略,并由
MultiCountryAddressValidator
实现。 通过访问对象实例,类级约束具有很大的灵活性,可以validation多个相关的属性。 请注意,这里排除了sorting,我们将在下一篇文章中回过头来看。专家组讨论了各种多属性支持方法:我们认为与涉及依赖性的其他属性级方法相比,类级约束方法提供了足够的简单性和灵活性。 欢迎您的反馈。
当您想要使用Beanvalidation规范时,需要一个类级validation器。 如果您很高兴使用Hibernatevalidation器function,则可以使用Validator-4.1.0.Final中提供的@ScriptAssert 。
要使用Beanvalidation正确工作,Pascal Thivent的答案中提供的示例可以被重写为:
@ValidAddress public class Address { @NotNull @Size(max = 50) private String street1; @Size(max = 50) private String street2; @NotNull @Size(max = 10) private String zipCode; @NotNull @Size(max = 20) private String city; @Valid @NotNull private Country country; // Getters and setters }
public class Country { @NotNull @Size(min = 2, max = 2) private String iso2; // Getters and setters }
@Documented @Target(TYPE) @Retention(RUNTIME) @Constraint(validatedBy = { MultiCountryAddressValidator.class }) public @interface ValidAddress { String message() default "{com.example.validation.ValidAddress.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
public class MultiCountryAddressValidator implements ConstraintValidator<ValidAddress, Address> { public void initialize(ValidateAddress constraintAnnotation) { } @Override public boolean isValid(Address address, ConstraintValidatorContext constraintValidatorContext) { Country country = address.getCountry(); if (country == null || country.getIso2() == null || address.getZipCode() == null) { return true; } switch (country.getIso2()) { case "FR": return // Check if address.getZipCode() is valid for France case "GR": return // Check if address.getZipCode() is valid for Greece default: return true; } } }