如何有条件地调用spring验证器

nil*_*esh 5 java validation spring

我有一个如下的模型.现有代码已经对各个属性进行了验证.现在我有一个要求,忽视billing_country和地址的现有验证,如果buyer.methodfoo.我以为我可以在buyer级别上有一个自定义验证器,检查方法并仅在调用时调用验证buyer.method!=foo.这是一种有效的方法吗?还有更好的选择吗?

"buyer": {
    "method": "foo",
    "instruments": [
      {
        "card": {
          "type": "MASTERCARD",
          "number": "234234234234234",
          "expire_month": "12",
          "expire_year": "2017",
          "billing_country" : "US"
          "Address" : {
             "line1": "summer st",
             "city": "Boston"
             "country": "US"
           }
        }
      }
    ]
}
Run Code Online (Sandbox Code Playgroud)

bee*_*jay 6

有两种方法可以做到这一点.

你也可以

  1. 创建一个自定义验证注释和验证器,用于检查其值,method然后将适当的验证应用于其他字段

  2. 使用验证组,您手动检查其值method,然后选择要使用的组; 然后,您的带注释的字段将需要更改为仅在该组处于活动状态时应用.

选项1

定义类级注释:

@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { MethodAndInstrumentsValidator.class })
@Documented
public @interface ValidMethodAndInstruments {
    String message() default "{my.package.MethodAndInstruments.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
Run Code Online (Sandbox Code Playgroud)

定义验证器:

public class MethodAndInstrumentsValidator 
             implements ConstraintValidator<ValidMethodAndInstruments, Buyer> {
    public final void initialize(final ValidMethodAndInstruments annotation) {
        // setup
    }

    public final boolean isValid(final Buyer value, 
                                 final ConstraintValidatorContext context) {
        // validation logic
        if(!"foo".equals(value.getMethod())) {
            // do whatever conditional validation you want
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

注释买方类:

@ValidMethodAndInstruments
public class Buyer { }
Run Code Online (Sandbox Code Playgroud)

选项#2

在这里,您必须手动调用验证.

首先,定义验证组:

public interface FooValidation {}
public interface NotFooValidation {}
Run Code Online (Sandbox Code Playgroud)

配置验证器:

@Bean
public LocalValidatorFactoryBean validatorFactory() {
    return new LocalValidatorFactoryBean();
}
Run Code Online (Sandbox Code Playgroud)

在您的控制器(?)中,检查值method并进行验证:

@Autowired
private Validator validator;

// ...

public void validate(Object a, Class<?>... groups) {
    Set<ConstraintViolation<Object>> violations = validator.validate(a, groups);
    if(!violations.isEmpty()) {
        throw new ConstraintViolationException(violations);
    }
}

// ...

validate(buyer, "foo".equals(buyer.getMethod()) 
                    ? FooValidation.class 
                    : NotFooValidation.class);
Run Code Online (Sandbox Code Playgroud)

最后,修改model/dto类中的组:

public class Buyer {
    // ...

    @Null(groups = FooValidation.class)
    @NotNull(groups = NotFooValidation.class)
    protected String billingCountry;
}
Run Code Online (Sandbox Code Playgroud)