9

我有一个要验证的表格。它包含 2 个地址变量。必须始终验证地址 1,必须根据某些条件验证地址 2

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

public class Address {
    @NotEmpty   
    private String street;
}

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

@RequestMapping(...)
public ModelAndView edit(
        @ModelAttribute("form")
        @Valid
        MyForm form,
        BindingResult bindingResult,
        ...)

        if(someCondition) {
            VALIDATE form.address2 USING JSR 303

问题是,如果我使用 LocalValidatorFactoryBean 验证器,我将无法重用 Spring 提供的 BinidingResult 对象。绑定不起作用,因为“结果”的目标对象是“MyForm”而不是“地址”

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

我想知道进行条件验证的标准/干净方法是什么。

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

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

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

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

4

3 回答 3

5

验证分层结构的标准方法是使用pushNestedPath()/ popNestedPath(),尽管我不确定它如何与 JSR-303 一起使用:

bindingResult.pushNestedPath("address2");
validate(form.getAddress2(), bindingResult);
bindingResult.popNestedPath();
于 2010-10-25T12:32:37.053 回答
1

I've never tried myself, but I think the correct approach is using validator groups.

于 2010-10-25T14:14:28.827 回答
0

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

将关联标记为 cascaded。关联对象将通过级联进行验证。

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

不幸的是,如果您需要验证某些组,您应该使用 Spring 原生验证器 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<ConstraintViolation<Object>> constraintViolationSet = validator.validate(command, groups);

        for(ConstraintViolation<Object> constraintViolation: constraintViolationSet) {
            errors.rejectValue(constraintViolation.getPropertyPath().toString(), null, constraintViolation.getMessage()); 
        }
    }

}
于 2010-10-26T04:18:37.073 回答