我有一个如下的模型。现有代码已经对各个属性进行了验证。现在,如果buyer.method
为foo
,我需要忽略billing_country和地址的现有验证。我以为我可以在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"
}
}
}
]
}
答案 0 :(得分:5)
有两种方法可以做到这一点。
你可以
创建自定义验证注释和验证器,用于检查method
的值,然后将适用的验证应用于其他字段
使用validation groups,您可以手动检查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 {};
}
定义验证器:
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
}
}
}
注明买方类:
@ValidMethodAndInstruments
public class Buyer { }
选项#2
在这里,您必须手动调用验证。
首先,定义验证组:
public interface FooValidation {}
public interface NotFooValidation {}
配置验证器:
@Bean
public LocalValidatorFactoryBean validatorFactory() {
return new LocalValidatorFactoryBean();
}
在你的控制器(?)中,检查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);
最后,修改model / dto类中的组:
public class Buyer {
// ...
@Null(groups = FooValidation.class)
@NotNull(groups = NotFooValidation.class)
protected String billingCountry;
}
答案 1 :(得分:0)
@beerbajay答案在一定程度上有所帮助,所以我将接受他的回答。不过,我还想记下他们提出的几个问题。我们无法在地址上使用@Null
和@NotNull
注释,因为它可能为null。其次,因为我们必须将它包装在自定义的Constraint验证器中,因此对于NotFooValidation.class
我们得到了不需要的额外验证消息字符串。最后,我们无法使用@Valid
中已存在的Address
中的群组。我们尝试了@Validated
,但由于某种原因这种做法并不奏效。我们最终实施ReaderInterceptor
来拦截请求并手动调用所需的验证。希望这有助于有人在路上。