简体   繁体   English

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

[英]Using JSR-303 annotations for conditional validation in Spring MVC

I have a form with ten fields, but a page displays only five fields initially. 我有一个包含十个字段的表单,但是页面最初只显示五个字段。 Remaining fields are hidden, and show up based on onChange event listener bound to other field. 其余字段被隐藏,并基于绑定到其他字段的onChange事件侦听器显示。

There are scenarios wherein it is possible to submit a form with just five not blank fields. 在某些情况下,可以提交仅包含五个非空白字段的表单。 In that case, validation has to be performed only for those five. 在那种情况下,仅需对这五个进行验证。 Sometimes, validation has to be performed for all fields (based on the state of that other field with onChange callback). 有时,必须对所有字段执行验证(基于具有onChange回调的其他字段的状态)。 Is there a way to filter field validation using annotations or should I write a custom validator? 有没有一种方法可以使用注释来过滤字段验证,还是应该编写自定义验证器?

Right now all ten form fields are validated. 现在,所有十个表单字段均已验证。 The rules are the following: 规则如下:

  • a,b,c,d,e are mandatory fields a,b,c,d,e是必填字段
  • f,g,h shows up only if a="111" f,g,h仅在a =“ 111”时显示
  • i,j shows up only if c="222" i,j仅在c =“ 222”时显示

Sample code: 样例代码:

@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;

Controller code: 控制器代码:

@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;
}
...///

You should be able to run validator manually and filter off errors which you don't want to return to client. 您应该能够手动运行验证器,并过滤掉不想返回给客户端的错误。 To be able to execute validator manually I had to add BindingResult as argument of rest method implementation. 为了能够手动执行验证程序,我必须添加BindingResult作为rest方法实现的参数。 Without BindingResult Spring framework didn't invoke method but returned validation errors to client. 没有BindingResult,Spring框架不会调用方法,但是会向客户端返回验证错误。

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

I could provide more accurate answer if you describe your controller. 如果您描述控制器,我可以提供更准确的答案。

Thanks for more details. 感谢您提供更多详细信息。 In my solution I removed @Valid annotation from controller definition so I have empty bindingResult. 在我的解决方案中,我从控制器定义中删除了@Valid批注,因此我的绑定结果为空。 Then I validate programmatically and pick out validation errors which I want to return to client. 然后,我以编程方式进行验证,并选择要返回给客户端的验证错误。

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);
        }
    }

You can validate mandatory fields via Bean Validation annotations, but for more complex conditional logic (ie f,g,h show up only if a="111" and i,j show up only if c="222" ) there is org.springframework.validation.Validator . 您可以通过Bean验证批注来验证必填字段,但是对于更复杂的条件逻辑(即f,g,h show up only if a="111" and i,j show up only if c="222" ),则存在org.springframework.validation.Validator

The example implementation in your case could be: 您的情况下的示例实现可能是:

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) is the same to @NotBlank behaviorwise. ValidationUtils.rejectIfEmptyOrWhitespace(Errors, String, String)@NotBlank行为方式相同。 Therefore do not annotate optional fields: 因此,请勿注释可选字段:

@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;

Your controller could look like: 您的控制器可能如下所示:

...

@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
}

...

Mandatory fields are validated with provided instance of type javax.validation.Validator through @Valid . 强制字段使用@Valid通过提供的类型javax.validation.Validator实例进行验证。 Encountered validation errors are put into BindingResult instance. 遇到的验证错误将放入BindingResult实例。 Then the conditional validation is performed via OneTimeFormValidator , and encountered validation errors are put into the same instance of BindingResult . 然后,通过OneTimeFormValidator执行条件验证,并将遇到的验证错误放入BindingResult的同一实例中。

I can suggest two ways to do that. 我可以建议两种方法。

You could create little models and validate against that. 您可以创建一些模型并对此进行验证。 On validation successful, you build your entity. 验证成功后,即可构建您的实体。

Or you could create your own validation constraint and validate the whole class onSubmit. 或者,您可以创建自己的验证约束并在onSubmit上验证整个类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM