有没有办法使用一个带有Spring 3注释控制器的多个Validator?

时间:2012-03-20 19:36:59

标签: java spring-mvc validation

我有一个扩展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()调用委托给它们,但这真的是最好的解决方案吗?

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

这是一个老问题。

在此处添加评论:

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

答案 2 :(得分:0)

我能想到的最好的解决方案是注入一组验证器,并自己手动旋转它们。所以现在我从控制器类中删除了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>