【问题标题】:Is there a way to use more than 1 Validator with a Spring 3 annotated Controller?有没有办法将多个验证器与 Spring 3 注释控制器一起使用?
【发布时间】:2012-04-05 07:49:46
【问题描述】:

我有一个扩展 SimpleFormController 的 Spring 2.x 控制器,它在 Spring 3 中已被弃用,取而代之的是带注释的控制器。所以我试图将其转换为使用@Controller,使用@InitBinder@Valid 进行表单验证。但是,我找不到将多个验证器与 Spring 3.x 控制器一起使用的方法。我该怎么做?

这是我的控制器的 bean def 当前的样子:

<bean name="/s/account" class="mywork.AccountSettingsController"
    p:formView="forms/account"
    p:successView="redirect:/app/s/account"
    p:commandName="accountSettingsForm">
    <property name="validators">
        <list>
            <ref bean="emailFormatValidator" />
            <ref bean="uniqueEmailValidator" />
            <ref bean="changeEmailValidator" />
            <ref bean="passwordWithConfirmationValidator" />
            <ref bean="changePasswordValidator" />
        </list>
    </property>
</bean>

它是一个页面控制器,允许用户更改他们的电子邮件地址和密码。验证器 bean 是遗留代码,但我猜它们被分成单独的类以提高可重用性。

我正在尝试使用注释将所有这些移入控制器类本身:

@Controller
@Secured({BaseController.ROLE_LOGGED_IN})
@RequestMapping("/s/account")
public class AccountSettingsController extends BaseController {
    private static final String FORM_URL = "/forms/account";
    private static final String FORM_NAME = "accountSettingsForm";

    @InitBinder(FORM_NAME)
    public void initBinder(WebDataBinder binder) {
        // TODO: how to inject > 1 validator for the form?
        binder.setValidator(...);
    }

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView get() {
        ChangePasswordOrEmailForm form = new ChangePasswordOrEmailForm();
        ...
        return new ModelAndView(FORM_URL, FORM_NAME, form);
    }
    ...
}

据我所知,Spring 3 假定以下之间存在一对一的关系:Controller-Form-WebDataBinder-Validator。我可以创建一个复合验证器来聚合 5 个单独的验证器 bean,并将 Validator#supports()Validator#validate() 调用委托给它们,但这真的是最好的解决方案吗?

【问题讨论】:

    标签: java spring-mvc validation


    【解决方案1】:

    这是一个老问题。

    在此处添加评论:

    春季 3.2.1.RELEASE 之后,DataBinder#addValidators(Validator... validators) 可用。

    【讨论】:

    • 谢谢,很高兴听到他们从 Spring Web MVC 2.x 中恢复了这个选项!
    【解决方案2】:

    另一个我认为是有一个 ValidatorFacade 依次调用所有其他验证器,这样您就不需要注入而是将 ValidatorFacade 与 initBinder 和 @Valid 附加在您的表单 bean 前面将自动调用ValidatorFacade 和一切都会自动处理。只是一个想法。

    【讨论】:

    • 你的意思是像this?我实际上在网上找到了一些不同的例子,所以我想这就是我要走的路。
    • 是的..我更喜欢使用 spring 的 autowire 而不是 xml 注入其他验证器,但想法是一样的。
    【解决方案3】:

    我能想到的最佳解决方案是注入一组验证器,然后自己手动旋转它们。所以现在我从我的控制器类中删除了initBinder(),这是我添加的内容:

    private List<Validator> accountSettingsValidators;
    
    // Maps & Collections can't be @Autowired (by type OR name), so use the JSR 250 @Resource annotation to autowire by name
    @Resource
    public void setAccountSettingsValidators(List<Validator> accountSettingsValidators) {
        this.accountSettingsValidators = accountSettingsValidators;
    }
    
    @RequestMapping(method = RequestMethod.POST)
    protected ModelAndView processSubmit(HttpServletRequest request,
                                         @ModelAttribute(FORM_NAME) ChangePasswordOrEmailForm form,
                                         BindingResult bindingResult) {
        for (Validator validator : this.accountSettingsValidators) {
            ValidationUtils.invokeValidator(validator, form, bindingResult);
        }
    
        if (bindingResult.hasErrors()) {
            return new ModelAndView(FORM_URL, FORM_NAME, form);
        }
    
        // process validated form
    }
    

    在我的formControllers.xml Spring 配置中,我创建了要注入的验证器列表:

    <util:list id="accountSettingsValidators">
        <ref bean="emailFormatValidator" />
        <ref bean="uniqueEmailValidator" />
        <ref bean="changeEmailValidator" />
        <ref bean="passwordWithConfirmationValidator" />
        <ref bean="changePasswordValidator" />
    </util:list>
    

    【讨论】:

      猜你喜欢
      • 2011-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 2010-12-23
      • 2014-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多