【问题标题】:Using JSR-303 annotations for conditional validation in Spring MVC在 Spring MVC 中使用 JSR-303 注释进行条件验证
【发布时间】:2016-11-22 15:17:50
【问题描述】:

我有一个包含十个字段的表单,但一个页面最初只显示五个字段。其余字段被隐藏,并根据绑定到其他字段的 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;
}
...///

【问题讨论】:

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


    【解决方案1】:

    您应该能够手动运行验证器并过滤掉您不想返回给客户端的错误。 为了能够手动执行验证器,我必须添加 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);
            }
        }
    

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

        您可以通过 Bean Validation 注释来验证必填字段,但对于更复杂的条件逻辑(即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的同一个实例中。

        【讨论】:

          【解决方案4】:
          猜你喜欢
          • 2018-01-30
          • 2014-06-24
          • 2011-04-30
          • 2011-10-29
          • 2014-03-24
          • 2011-05-10
          • 2012-05-12
          • 2018-08-15
          • 1970-01-01
          相关资源
          最近更新 更多