有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我正在使用JPA2.0/Hibernate验证来验证我的模型。我现在遇到一种情况,必须验证两个字段的组合:

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

如果getValue1()getValue2()都是null的,则该模型是无效的,否则是有效的

如何使用JPA2.0/Hibernate执行这种验证?对于简单的@NotNull注释,两个getter都必须为非null才能通过验证


共 (5) 个答案

  1. # 1 楼答案

    为了正确使用Bean Validation,Pascal Thivent的answer中提供的示例可以重写如下:

    @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;
            }
        }
    }
    
  2. # 2 楼答案

    您可以像这样使用@AssertTrue验证:

    public class MyModel {
        
        // values
    
        @AssertTrue(message = "Values are invalid")
        private String isValid() {
          return value1 != null || value2 != null;
        }
    }
    
  3. # 3 楼答案

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

    Class-level constraints

    Some of you have expressed concerns about the ability to apply a constraint spanning multiple properties, or to express constraint which depend on several properties. The classical example is address validation. Addresses have intricate rules:

    • a street name is somewhat standard and must certainly have a length limit
    • the zip code structure entirely depends on the country
    • the city can often be correlated to a zipcode and some error checking can be done (provided that a validation service is accessible)
    • because of these interdependencies a simple property level constraint does to fit the bill

    The solution offered by the Bean Validation specification is two-fold:

    • it offers the ability to force a set of constraints to be applied before an other set of constraints through the use of groups and group sequences. This subject will be covered in the next blog entry
    • it allows to define class level constraints

    Class level constraints are regular constraints (annotation / implementation duo) which apply on a class rather than a property. Said differently, class-level constraints receive the object instance (rather than the property value) in 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<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;
            }
            // ...
        }
    }
    

    The advanced address validation rules have been left out of the address object and implemented by MultiCountryAddressValidator. By accessing the object instance, class level constraints have a lot of flexibility and can validate multiple correlated properties. Note that ordering is left out of the equation here, we will come back to it in the next post.

    The expert group has discussed various multiple properties support approaches: we think the class level constraint approach provides both enough simplicity and flexibility compared to other property level approaches involving dependencies. Your feedback is welcome.

  4. # 4 楼答案

    当您希望继续使用Bean验证规范(例如here)时,定制类级验证器是一个不错的选择

    如果您愿意使用Hibernate验证器功能,那么可以使用自Validator-4.1.0以来提供的@ScriptAssert。最终的除了JavaDoc之外:

    Script expressions can be written in any scripting or expression language, for which a JSR 223 ("Scripting for the JavaTM Platform") compatible engine can be found on the classpath.

    例如:

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

    编程语言:Java

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

    要求:

    1. 在UI上有一个表,其中包含对象列表,这些对象正在映射到具有fk关系的多个表/对象

    2. 现在验证已超出多个FK,只有3列无法复制。我的意思是3的组合不能复制

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

    解决方案:

    我准备了一个字符串,它是一个自定义字符串,包含FK1的ID#FK2的ID#FK3的ID 例如:字符串的形式类似->;1000L#3000L#1300L#

    对于这个字符串,我们将使用set的add()将其添加到一个集合中,如果出现重复,该集合将返回false

    基于此标志,我们可以抛出验证消息

    这对我有帮助。在某些情况下,DS可能没有帮助