在Spring MVC中使用JSR-303注释进行条件验证

时间:2016-07-19 15:59:58

标签: java spring spring-mvc bean-validation spring-validator

我有一个包含十个字段的表单,但页面最初只显示五个字段。隐藏剩余字段,并根据绑定到其他字段的onChange事件侦听器显示。

在某些情况下,可以提交仅包含五个非空白字段的表单。在这种情况下,必须仅对这五个进行验证。有时,必须对所有字段执行验证(基于具有onChange回调的其他字段的状态)。有没有办法使用注释过滤字段验证,还是应该编写自定义验证器?

现在所有十个表单字段都经过验证。 规则如下:

  • a,b,c,d,e是必填字段
  • f,g,h仅在a =" 111"
  • 时显示
  • i,j仅在c =" 222"
  • 时出现

示例代码:

@NotBlank
private String a;
@NotBlank
private String b;
@NotBlank
private String c;
@NotBlank
private String d;
@NotBlank
private String e;

@NotBlank(a="111")
private String f;
@NotBlank(a="111")
private String g;
@NotBlank(a="111")
private String h;
@NotBlank(c="222")
private String i;
@NotBlank(c="222")
private String j;

控制器代码:

@RequestMapping(value="/payments/getTax.do", method=RequestMethod.POST) 
public String getTaxInfo(@Valid OneTimeForm command, BindingResult result, 
    Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {        


OneTimeForm oneTimeForm = (OneTimeForm) command;        

try {
    validator.validate(oneTimeForm, result);
} catch (ValidationException ex) {  
    throw ex;
}
...///

4 个答案:

答案 0 :(得分:2)

您应该能够手动运行验证程序并过滤掉您不想返回客户端的错误。 为了能够手动执行验证器,我必须添加BindingResult作为rest方法实现的参数。没有BindingResult Spring框架没有调用方法,但是将验证错误返回给客户端。

@RequestMapping(method = PATCH, value = "/{id}")
public ResponseEntity<User> patchUser(@RequestBody User patchUser,
                                      BindingResult bindingResult)  {

如果您描述控制器,我可以提供更准确的答案。

感谢您提供更多详情。 在我的解决方案中,我从控制器定义中删除了@Valid注释,因此我有空的bindingResult。然后我以编程方式验证并选择我想要返回给客户端的验证错误。

BindingResult allErrors = new BeanPropertyBindingResult(target, objectName);
//validate and copy relevant errors into bindingResult
validator.validate(target, allErrors);
for (FieldError fe : allErrors.getFieldErrors()) {
        if (/* your conditions */) {
            bindingResult.addError(fe);
        }
    }

答案 1 :(得分:2)

您可以通过Bean验证注释验证必填字段,但对于更复杂的条件逻辑(即f,g,h show up only if a="111" and i,j show up only if c="222"),有org.springframework.validation.Validator

您的案例中的示例实现可能是:

public class OneTimeFormValidator implements org.springframework.validation.Validator {

    @Override
    public boolean supports(Class clazz) {
       return OneTimeForm.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        final OneTimeForm form = (OneTimeForm) target;
        if ("111".equals(form.getA())) {
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "f", "f.required");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "g", "g.required");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "h", "h.required");
        }
        if ("222".equals(form.getC())) {
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "i", "i.required");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "j", "j.required");
        }
    }
 }

ValidationUtils.rejectIfEmptyOrWhitespace(Errors, String, String)@NotBlank行为相同。因此,请勿注释可选字段:

@NotBlank
private String a;
@NotBlank
private String b;
@NotBlank
private String c;
@NotBlank
private String d;
@NotBlank
private String e;

private String f;
private String g;
private String h;
private String i;
private String j;

您的控制器可能如下所示:

...

@Autowired
private org.springframework.validation.Validator oneTimeFormValidator;

@RequestMapping(value="/payments/getTax.do", method=RequestMethod.POST)  
public String getTaxInfo(@Valid OneTimeForm command, BindingResult result) { 

     // validates conditional logic with OneTimeFormValidator
     oneTimeFormValidator.validate(command, result);

     if (result.hasErrors()) {
         // return a page
     }
     // do something else and return a page
}

...

使用提供的javax.validation.Validator@Valid类型的实例验证必填字段。遇到的验证错误被放入BindingResult实例中。然后通过OneTimeFormValidator执行条件验证,并将遇到的验证错误放入BindingResult的同一个实例中。

答案 2 :(得分:0)

我可以建议两种方法来做到这一点。

您可以创建小模型并对其进行验证。验证成功后,您将构建实体。

或者您可以创建自己的验证约束并在onSubmit上验证整个类。

答案 3 :(得分:0)