如何组合验证两个或多个字段?

我正在使用 JPA 2.0/Hibernate 验证来验证我的模型。我现在遇到的情况是,两个字段的组合必须得到验证:

public class MyModel {
public Integer getValue1() {
//...
}
public String getValue2() {
//...
}
}

如果 getValue1()getValue2()都是 null并且在其他情况下有效,则模型为 无效

如何使用 JPA 2.0/Hibernate 执行这种验证?使用简单的 @NotNull注释,两个 getter 都必须是非 null 才能通过验证。

140512 次浏览

对于多个属性验证,应使用类级别约束 Bean Validation Sneak Peek part II: custom constraints:

类级别约束

你们有些人表达了担忧 关于应用 constraint spanning multiple 属性,或表示约束 取决于几个属性。 The classical example is address 验证。地址有错综复杂的 规则:

  • 街道名称有些标准,必须有一定的长度限制
  • 邮政编码的结构完全取决于国家
  • 城市往往可以相关的邮政编码和一些错误检查可以 (如果有效性验证) 服务)
  • because of these interdependencies a simple property level constraint does to fit the bill

Bean 提供的解决方案 Validation specification is two-fold:

  • 它提供了强制一组约束在 其他约束 群和群序列的使用。 本主题将在 下一篇博文
  • 它允许定义类级约束

Class level constraints are regular 约束(注释/ 实施二人制) 阶级而不是财产 不同的,类级别的约束 接收对象实例(相当于 比属性值大)。

@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<AddressAnnotation, Address> {
public void initialize(AddressAnnotation constraintAnnotation) {
// initialize the zipcode/city/country correlation service
}


/**
* Validate zipcode and city depending on the country
*/
public boolean isValid(Address object, ConstraintValidatorContext context) {
if (!(object instanceof Address)) {
throw new IllegalArgumentException("@AddressAnnotation only applies to Address objects");
}
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;
}
// ...
}
}

高级地址验证规则 没有写在地址上 对象,并由 MultiCountryAddressValidator 访问对象实例、类 水平约束有很多 灵活性,可以验证多个 相关性,请注意 排序被排除在等式之外 在这里,我们将回到它在 下一篇。

专家组讨论了各种 多属性支持 方法: 我们认为班级水平 约束方法同时提供了 足够的简单性和灵活性 与其他财产水平相比 approaches involving dependencies. 欢迎你的反馈。

当您希望继续使用 Bean 验证规范(例如 给你)时,可以使用自定义类级验证器。

如果您愿意使用 Hibernate Validator 特性,那么可以使用 Rel = “ noReferrer”>@ScriptAssert ,它是在 Validator-4.1.0之后提供的。最终决定。除了它的 JavaDoc:

Script expressions can be written in any scripting or expression 语言,其中 JSR 223(“ JavaTM 平台脚本”) 可以在类路径上找到兼容的引擎。

例如:

@ScriptAssert(lang = "javascript", script = "_this.value1 != null || _this != value2)")
public class MyBean {
private String value1;
private String value2;
}

为了正确使用 豆子验证,帕斯卡 · 蒂文特的 回答中提供的例子可以重写如下:

@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(ValidAddress 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;
}
}
}

编程语言: Java

这是一个对我有帮助的解决方案。

要求:

  1. 在 UI 上有一个包含对象列表的表,它具有映射到多个具有 fk 关系的表/对象。

  2. 现在验证已经不需要多个 fk 了,只有3个列不能被复制。我的意思是3的组合不能被复制。

注意: 由于我正在从事 Java 自定义框架的工作,因此没有使用 HashCode 或 equals 的选项。如果我将使用数组索引迭代,这将增加我不想要的时间复杂性。

解决方案:

我已经准备了一个 String,它是一个自定义 String,包含 ID 为 FK1 # ID 为 FK2 # ID 为 FK3的 ID Ex: the String will form like -> 1000L#3000L#1300L#

这个字符串,我们将通过使用 set 的 add ()添加到 set 中,如果出现重复,它将返回 false。

根据这个标志,我们可以抛出验证消息。

This helped me. Some scenario and restriction comes where DS may not help.

您可以像下面这样使用 @javax.validation.constraints.AssertTrue验证:

public class MyModel {
    

private String value1;
private String value2;


@AssertTrue(message = "Values are invalid")
private boolean isValid() {
return value1 != null || value2 != null;
}
}