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

时间:2014-05-07 08:25:43

标签: java spring-mvc bean-validation

我制定了一个概念,使用JSR 303组有条件地验证。 “有条件地”意味着我有一些字段仅在另一个字段具有特定值时才相关。

示例:可以选择是注册为个人还是注册为公司。选择公司时,用户必须填写包含公司名称的字段。

现在我以为我会使用群组:

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

在我的控制器中,我会根据相应的选择逐步验证:

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

我只想验证必须验证的内容。如果用户选择“公司”填写具有无效内容的字段,然后切换回“用户”,则验证者必须忽略无效的公司相关内容。解决方案是使用Javascript清除这些字段,但我也希望我的表单能够禁用javascript。这就是为什么我完全喜欢上面显示的方法。

但是由于数据绑定,Spring打破了这个想法。在验证开始之前,Spring将数据绑定到registerForm。例如,如果类型不兼容(预期的int值,但用户用字母填充表单),它会向result添加错误。这是一个问题,因为<form:errors />标记

在JSP视图中显示了这些错误

现在我找到了一种方法来阻止Spring通过实现自定义BindingErrorProcessor将这些错误添加到绑定结果中。如果字段包含null,我知道存在验证错误。在我的概念中null是不允许的 - 每个字段都使用@NotNull加上相应的验证组进行注释。

由于我是Spring和JSR-303的新手,我想知道,我是否完全走错了路。事实上,我必须自己实施一些事情让我不确定。这是一个干净的解决方案?对于同样的问题,是否有更好的解决方案,因为我认为这是一个常见的问题?

修改

如果您对我的解决方案感兴趣,请在此处查看我的答案:https://stackoverflow.com/a/30500985/395879

2 个答案:

答案 0 :(得分:0)

你认为Spring MVC在这方面有点挑剔是正确的,这是一个常见的问题。但有一些解决办法:

  • 制作所有支持字段字符串,并手动执行数字/日期等转换和空检查。
  • 当字段变得无关紧要时,使用JavaScript将字段设置为null。
  • 使用JavaScript在输入字段时对其进行验证。这将解决几乎所有问题。
祝你好运!

答案 1 :(得分:0)

我知道这个问题已经过时了,但是我找到了解决不同情况的答案。

我认为根据您的情况,您可以对表单使用继承,然后使用两个控制器方法:

表单如下所示:

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

控制器方法如下所示:

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

请注意,@RequestMapping注释包含params属性,因此isCompany参数的值决定了调用哪个方法。

另请注意,@Valid注释位于form参数上。

最后,在这种情况下不需要任何组。