3

我正在从 Spring 2.5 升级到 Spring 3.2。我有一个以前扩展的 MVC 控制器CancellableFormController。它分别声明initBinder()onBind()方法。我已将 Controller 重构为使用@Controller注释,并将覆盖的initBinder()方法切换为使用 Spring MVC 3 注释@initBinder

我的具体问题是,在 Spring MVC 3 中,从 Spring 2.5 升级,如何重构被覆盖的onBind()方法以使用等效的注解?现有方法的签名是:

@Override
protected void onBind(HttpServletRequest request, Object command, BindException errors)  throws Exception {
    MyCommand cmd = (MyCommand) command;
    ....
}

我考虑过使用@initBinder()并将之前的代码onBind()放在这个带注释的方法中。但我的困惑是:

  1. 这样做,会不会像以前一样在整个框架过程中同时调用代码?
  2. 如何从带@initBinder注释的方法中获取 Command 对象的句柄。

我可以将它声明为方法签名中的另一个参数,Spring MVC 框架将确保我得到一个副本吗?似乎在旧onBind()方法中已经(通过formBackingObject方法)创建了 Command 对象。我可以安全地假设使用@initBinder方法时也是如此吗?

谢谢大家的一些见解。我正在尝试跟上 Spring MVC 流程的速度!

我现有的@initBinder方法签名是这样的:

@InitBinder
protected void initBinder(WebDataBinder binder) {
    // register custom editor here.. etc
}

我希望我可以做类似的事情:

@InitBinder
protected void initBinder(WebDataBinder binder, MyCommand cmd) {
   // register custom editor here.. etc
}

这是使用注释升级cancellableformcontroller onBind() 方法的标准最佳实践方法吗?

根据标记为正确的答案进行尝试,但仍然无法正常工作:

@InitBinder("myCommand")
protected void onBind(WebDataBinder binder) throws Exception {
    MyCommand cmd = (MyCommand) binder.getTarget();
    .... // do whatever was required here...
}

解决方法

请参阅下面我对 zeroflag 的评论。创建一个与 onBind() 中包含的逻辑相同的私有方法,然后在 onSubmit() 注释方法 (POST / GET) 中验证命令对象后,调用现已失效的 onBind() 方法,将您的命令对象作为范围。类似于以下内容:

@RequestMapping(method=RequestMethod.POST) 
public ModelAndView onSubmit(@ModelAttribute("myCommand") MyCommand cmd, BindingResult result, <any other params> {
    
        new MyCommandValidator().validate(cmd, result);
        if (result.hasErrors()) {
            return new ModelAndView("context");
        }
        onBind(cmd, <any other params>);

        ... // do business stuff

}

对于我的特定情况,这似乎是一个丑陋的解决方法。

4

1 回答 1

1

您可以使用 访问命令对象binder.getTarget()@InitBinder为控制器方法的每个模型参数调用。让我们假设以下代码

@RequestMapping("/somePath")
public String myMethod(@ModelAttribute("user") User user,
                       @ModelAttribute("info") Info info) {

然后你的initBinder方法至少被调用两次:User对象和Info对象。要仅针对特定对象调用它,请添加模型名称:

@InitBinder("user")

这样它只会被User对象调用。但请注意,该方法可能仍会被多次调用,即使目标对象为空也是第一次。

如果您想确保某些字段不会自动设置,那么您可以setDisallowedFields()在您的initBinder方法中使用。

如果您想做一些验证,那么让 JSR 303(Bean 验证)来完成这项工作。

根据您想要@ModelAttribute在控制器中执行的方法可能是一个解决方案:

@ModelAttribute("user")
public User createUser(HttpServletRequest request /*or whatever*/) {
  User user = new User();
  //check some parameters and set some attributes
  return user;
}

在绑定发生之前创建一个用户对象。

最后一个解决方案可以是命令对象的消息或类型转换器,它根据请求创建对象。这实际上类似于上面的示例,但独立于控制器,并且对于使用转换器创建的对象没有绑定。

于 2013-04-30T09:29:16.353 回答