【问题标题】:Spring Bean Validation with configurable constraint values具有可配置约束值的 Spring Bean 验证
【发布时间】:2019-11-17 03:26:11
【问题描述】:

我想让 Java Bean Validation 约束可由 Spring 配置,可能通过使用属性。一个例子:

class Pizza {

    @MaxGramsOfCheese(max = "${application.pizza.cheese.max-grams}")
    int gramsOfCheese;

}

我无法让它工作或找到很多关于这个的文档。

这样的事情可能吗?我知道消息可以在 Validationmessages.properties 文件中进行配置,所以我希望约束值也可以有类似的东西。

【问题讨论】:

    标签: java spring bean-validation


    【解决方案1】:

    对于任何自定义验证,您需要通过实现ConstraintValidator 接口来实现一个自定义验证器,然后将该自定义验证器提供给您创建的自定义验证注释。

    自定义验证器:

    public class MaxGramsOfCheeseValidator implements ConstraintValidator<MaxGramsOfCheese, Integer> {
    
        @Value("${application.pizza.cheese.max-grams}")
        protected int maxValue;
    
        @Override
        public void initialize(MaxGramsOfCheese constraintAnnotation) {
        }
    
        @Override
        public boolean isValid(Integer value, ConstraintValidatorContext context) {
            return value != null && value <= maxValue;
        }
    
    }
    

    自定义验证注解:

    @Documented
    @Constraint(validatedBy = {MaxGramsOfCheeseValidator.class})
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MaxGramsOfCheese {
        String message() default "Some issue here"; //message to be returned on validation failure
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    

    使用自定义验证注解:

    class Pizza {
    
        @MaxGramsOfCheese
        int gramsOfCheese;
    
    }
    

    请注意,如果您希望从属性文件中访问注释的值,则必须在自定义验证器中提供该值,如图所示。

    【讨论】:

      【解决方案2】:

      除了@Madhu Bhat,您还可以配置ConstraintValidator 类以从Spring 的Environment 中读取属性。

      public class MaxGramsOfCheeseValidator implements ConstraintValidator<MaxGramsOfCheese, Integer> {
      
          @Autowired
          private Environment env;
      
          private int max;
      
          public void initialize(MaxGramsOfCheese constraintAnnotation) {
              this.max = Integer.valueOf(env.resolvePlaceholders(constraintAnnotation.max()));
          }
      
          @Override
          public boolean isValid(Integer value, ConstraintValidatorContext context) {
              return value != null && value <= this.max;
          }
      
      }
      

      因此,您可以在具有不同参数的不同字段上使用 @MaxGramsOfCheese 注释,这可能更适合您的情况。

      class Pizza {
      
          @MaxGramsOfCheese(max = "${application.pizza.cheddar.max-grams}")
          int gramsOfCheddar;
      
          @MaxGramsOfCheese(max = "${application.pizza.mozerella.max-grams}")
          int gramsOfMozerella;
      
      }
      

      【讨论】:

      • 我喜欢这个解决方案,因为它可以通过属性或固定值保持最大可配置(尽管这需要编程)。不幸的是,这不起作用:java.lang.NumberFormatException: For input string: "${application.pizza.cheddar.max-grams}".
      • 这可能是因为您的application.properties 文件中没有属性定义。您可以简单地定义一个默认值,例如${application.pizza.cheddar.max-grams:5}。此外,您可以在MaxGramsOfCheeseValidator 中将方法env.resolvePlaceholders 更改为env.resolveRequiredPlaceholders。当没有找到与您添加到注释的键相关的属性时,这将强制抛出 IllegalArgumentException。因此,您可以根据需要处理这种情况,或者只记录警告。
      • 我在 application.yml 中定义了属性。似乎这些没有正确读取。当更改为 application.properties 时,它可以工作。
      • 很高兴它可以工作:) 通常它应该可以工作很奇怪。如果您同时拥有.properties.yml,那么对于相同的键.properties 文件将覆盖.yml 之一。也许是这样,但我不确定。
      • 如果我使用自己的属性文件,比如 myprops.properties,会怎样?该文件也在资源文件夹中,如何通过环境访问它?还是需要其他解决方案?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-30
      • 1970-01-01
      • 2019-01-07
      • 1970-01-01
      相关资源
      最近更新 更多