Spring MVC和JSR-303 hibernate条件validation

我有一个我要validation的表单。 它包含2个地址变量。 始终要validationaddress1,必须根据某些条件validationaddress2

public class MyForm { String name; @Valid Address address1; Address address2; } public class Address { @NotEmpty private String street; } 

我的控制器自动validation并绑定我的表单obj

 @RequestMapping(...) public ModelAndView edit( @ModelAttribute("form") @Valid MyForm form, BindingResult bindingResult, ...) if(someCondition) { VALIDATE form.address2 USING JSR 303 

问题是,如果我使用LocalValidatorFactoryBeanvalidation器,我无法重用Spring提供的BinidingResult对象。 绑定不起作用,因为’result’的目标对象是’MyForm’而不是’Address’

 validate(form.getAddress2(), bindingResult) //won't work 

我想知道什么是标准/清洁方法来进行条件validation。

我正在考虑以编程方式在我的控制器中创建一个新的BindingResult。

 final BindingResult bindingResultAddress2 = new BeanPropertyBindingResult(address2, "form"); validate(form.getAddress2(), bindingResultAddress2); 

但是我从bindingResultAddress2获得的错误列表无法添加到一般的’bindingResult’,因为字段名称不正确(’street’而不是’address2.street’),绑定将不起作用。

一些肮脏的方法是扩展BeanPropertyBindingResult以接受一些字符串附加到字段名称..你有更好的方法吗?

validation层次结构的标准方法是使用pushNestedPath() / popNestedPath() ,虽然我不确定它如何与JSR-303一起使用:

 bindingResult.pushNestedPath("address2"); validate(form.getAddress2(), bindingResult); bindingResult.popNestedPath(); 

我从未尝试过自己,但我认为正确的方法是使用validation器组 。

首先,让我们看看@ javax.validation.Valid API

将关联标记为级联 。 关联的对象将通过级联validation。

当Spring框架使用@Valid 作为标记来validation其命令对象时,它会破坏其目的。 Spring应该创建自己的特定注释,指定应该validation的组。

不幸的是,如果需要validation某些组,则应使用Spring本机Validator API

 public void doSomething(Command command, Errors errors) { new BeanValidationValidator(SomeUserCase.class, OtherUserCase.class) .validate(command, errors); if(errors.hasErrors()) { } else { } } 

BeanValidationValidator可以实现为

 public class BeanValidationValidator implements Validator { javax.validation.Validator validator = ValidatorUtil.getValidator(); private Class [] groups; public BeanValidationValidator(Class... groups) { this.groups = groups; } public void validate(Object command, Errors errors) { Set> constraintViolationSet = validator.validate(command, groups); for(ConstraintViolation constraintViolation: constraintViolationSet) { errors.rejectValue(constraintViolation.getPropertyPath().toString(), null, constraintViolation.getMessage()); } } }