用于onBind()的Spring MVC 3 Controller注释 - 如何?

时间:2013-04-30 05:13:28

标签: java spring spring-mvc spring-mvc-initbinders

我正在从Spring 2.5升级到Spring 3.2。我有一个以前扩展CancellableFormController的MVC控制器。它分别声明了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对象的句柄。
  3. 我可以将它声明为方法签名中的另一个参数,Spring MVC框架将确保我得到一个副本吗?似乎在旧onBind()方法中已经创建了Command对象(通过formBackingObject方法)。我可以安全地假设使用@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()方法,将Command对象作为一个传递给参数。如下所示:

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

    这似乎是一个丑陋的解决方法,对我的具体情况来说是好的。

1 个答案:

答案 0 :(得分: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 Validation)完成这项工作。

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

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

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

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