简体   繁体   English

JSR-303 / Spring MVC-使用组有条件地验证

[英]JSR-303 / Spring MVC - validate conditionally using groups

I worked out a concept to conditionally validate using JSR 303 groups. 我提出了一个概念,可以有条件地使用JSR 303组进行验证。 "Conditionally" means that I have some fields which are only relevant if another field has a specific value. “有条件地”表示我有一些仅在另一个字段具有特定值的情况下才相关的字段。

Example: There is an option to select whether to register as a person or as a company. 示例:有一个选项可以选择是注册为个人还是公司。 When selecting company, the user has to fill a field containing the name of the company. 选择公司时,用户必须填写包含公司名称的字段。

Now I thought I use groups for that: 现在我认为我可以使用组:

  class RegisterForm
  {
     public interface BasicCheck {}
     public interface UserCheck {}
     public interface CompanyCheck {}

     @NotNull(groups = BasicCheck.class)
     private Boolean isCompany

     @NotNull(groups = UserCheck.class)
     private String firstName;

     @NotNull(groups = UserCheck.class)
     private String lastName;

     @NotNull(groups = CompanyCheck.class)
     private String companyName;

     // getters / setters ...
  }

In my controller, I validate step by step depending on the respective selection: 在我的控制器中,我会根据各自的选择逐步验证:

  @Autowired
  SmartValidator validator;

  public void onRequest(@ModelAttribute("registerForm") RegisterForm registerForm, BindingResult result)
  {
     validator.validate(registerForm, result, RegisterForm.BasicCheck.class);
     if (result.hasErrors()
        return;
     // basic check successful => we can process fields which are covered by this check
     if (registerForm.getIsCompany())
     {
        validator.validate(registerForm, result, RegisterForm.CompanyCheck.class)
     }
     else
     {
        validator.validate(registerForm, result, RegisterForm.UserCheck.class);
     }
     if (!result.hasErrors())
     {
        // process registration
     }
  }

I only want to validate what must be validated. 我只想验证必须验证的内容。 If the user selects "company" fills a field with invalid content and then switches back to "user", the invalid company related content must be ignored by the validator. 如果用户选择“公司”,则使用无效内容填充字段,然后切换回“用户”,验证程序必须忽略与公司相关的无效内容。 A solution would be to clear those fields using Javascript, but I also want my forms to work with javascript disabled. 一种解决方案是使用Javascript清除这些字段,但我也希望表单在禁用javascript的情况下工作。 This is why I totally like the approach shown above. 这就是为什么我完全喜欢上面显示的方法的原因。

But Spring breaks this idea due to data binding. 但是由于数据绑定,Spring打破了这个想法。 Before validation starts, Spring binds the data to registerForm. 在验证开始之前,Spring将数据绑定到registerForm。 It adds error to result if, for instance, types are incompatible (expected int-value, but user filled the form with letters). 例如,如果类型不兼容(预期的整数值,但用户用字母填充表格),则会在result增加错误。 This is a problem as these errors are shown in the JSP-view by <form:errors /> tags 这是一个问题,因为这些错误在<form:errors />标记在JSP视图中显示

Now I found a way to prevent Spring from adding those errors to the binding result by implementing a custom BindingErrorProcessor . 现在,我找到了一种方法,可以通过实现自定义BindingErrorProcessor来防止Spring将这些错误添加到绑定结果中。 If a field contains null I know that there was a validation error. 如果字段包含null我知道存在验证错误。 In my concept null is not allowed - every field gets annotated with @NotNull plus the respective validation group. 在我的概念null是不允许的-每场得到带注释@NotNull加上相应的验证组。

As I am new to Spring and JSR-303 I wonder, whether I am totally on the wrong path. 当我刚接触Spring和JSR-303时,我想知道自己是否完全走错了道路。 The fact that I have to implement a couple of things on my own makes me uncertain. 我必须自己执行几件事,这使我不确定。 Is this a clean solution? 这是一个干净的解决方案吗? Is there a better solution for the same problem, as I think this is a common problem? 我认为这是一个普遍的问题,对于同一问题是否有更好的解决方案?

EDIT 编辑

Please see my answer here if you are interested in my solution in detail: https://stackoverflow.com/a/30500985/395879 如果您对我的解决方案感兴趣,请在这里查看我的答案: https : //stackoverflow.com/a/30500985/395879

You are correct that Spring MVC is a bit picky in this regard,and it is a common problem. 您是正确的,Spring MVC在这方面有点挑剔,这是一个普遍的问题。 But there are work-arounds: 但是有解决方法:

  • Make all your backing fields strings, and do number/date etc conversions and null checks manually. 将所有后备字段设置为字符串,并手动进行数字/日期等转换和空值检查。
  • Use JavaScript to set fields to null when they become irrelevant. 当字段不相关时,使用JavaScript将其设置为null。
  • Use JavaScript to validate fields when they are entered. 输入字段时,使用JavaScript验证字段。 This will fix almost all of your problems. 这将解决您几乎所有的问题。

Good luck! 祝好运!

I know this question is old, but I came upon it looking for an answer for a different situation. 我知道这个问题很旧,但是我遇到了这个问题,正在寻找其他情况的答案。

I think for your situation you could use inheritance for the forms and then use two controller methods: 我认为根据您的情况,您可以对表格使用继承,然后使用两种控制器方法:

The forms would look like this: 表格如下所示:

public class RegistrationForm
{
    // Common fields go here.
}

public class UserRegistrationForm
    extends RegistrationForm
{
    @NotNull
    private String firstName;

    @NotNull
    private String lastName;

    // getters / setters ...
}

public class CompanyRegistrationForm
    extends RegistrationForm
{
    @NotNull
    private String companyName;

    // getters / setters ...
}

The controller methods would look like this: 控制器方法如下所示:

@RequestMapping(method = RequestMethod.POST, params = "isCompany=false")
public void onRequest(
        @ModelAttribute("registerForm") @Valid UserRegistrationForm form,
        BindingResult result)
{
    if (!result.hasErrors())
    {
        // process registration
    }
}
@RequestMapping(method = RequestMethod.POST, params = "isCompany=true")
public void onRequest(
        @ModelAttribute("registerForm") @Valid CompanyRegistrationForm form,
        BindingResult result)
{
    if (!result.hasErrors())
    {
        // process registration
    }
}

Notice that the @RequestMapping annotations include a params attribute so the value of the isCompany parameter determines which method is called. 注意, @RequestMapping注释包括一个params属性所以值isCompany参数确定哪个方法被调用。

Also notice that the @Valid annotation is place on the form parameter. 还要注意,@ @Valid批注位于form参数上。

Finally, no groups are needed in this case. 最后,在这种情况下,不需要任何组。

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

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