【问题标题】:Spring MVC 3 Controller annotation for onBind() - how to?onBind() 的 Spring MVC 3 Controller 注释 - 如何?
【发布时间】:2013-04-30 05:13:27
【问题描述】:

我正在从 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 对象的句柄。

我可以将它声明为方法签名中的另一个参数,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...
}

解决方法

请在下面查看我的 cmets 到 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

}

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

【问题讨论】:

  • 在我回答之前:为什么要访问命令对象?我很确定在当前的 Spring MVC 中有一个更“自动”的解决方案 :)
  • 感谢您抽出时间和精力来提问。基本上,这是继承的代码(大约 5 年前的旧版应用程序),因此确切的上下文丢失了。从我阅读的内容来看,最初的目的是检查Command对象,并读取几个属性,然后最后更新命令对象中的一些信息。现在,为什么这必须发生在 onBind() 而不是过程中的其他一些钩子方法还不是很清楚。让我们假设用户希望确保命令对象在绑定时完全更新;)你知道 Spring MVC 3 中带有注释的等效机制吗?
  • @zeroflagL - 请参阅上面的评论。

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


【解决方案1】:

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

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

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

@InitBinder("user")

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

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

如果您想做一些验证,那么让 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;
}

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

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

【讨论】:

  • 相信你的答案的第一部分正是我需要知道的。请允许我一点时间来更新我的代码和测试。一切顺利,我会将这个答案标记为正确答案。感谢帮助!
  • 很抱歉花了这么长时间来更新我的代码并检查您的解决方案。是的,这是正确的答案并解决了我的问题。应根据您的解决方案使用我使用的解决方案更新我的问题。谢谢!
  • 好的,最后,我发现这不能按预期工作。从 getTarget() 返回的命令对象未填充值。而使用 onBind() 它传递表单填充值(作为命令对象内的属性)并在 onSubmit() 之前被调用。
  • @user36123 它被称为initBinder 是有原因的;)这就是我提供更多选项的原因。您能否发布您当前onBind() 方法的相关代码?然后我们可以为您的应用找出最佳的迁移路径。
  • zeroflagL - 再次感谢您提供进一步的见解。我最终实现了我所需要的,只需在控制器中创建一个私有/受保护的方法,该方法包含与之前的 onBind 相同的逻辑,并使用带注释的 (POST) onSubmit() 方法显式调用它,并将命令对象作为参数传递。这是一个警察,也许没有像以前那样使用 Spring 框架模板方法来获得精确的时间(尽管它“看起来” onBind 是在旧控制器中的 onSubmit 之前被调用的),但它满足了我在这种情况下的特定要求。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2012-02-17
  • 2012-11-11
  • 1970-01-01
  • 2023-03-17
  • 2012-08-12
  • 1970-01-01
  • 2018-07-07
  • 2011-10-17
相关资源
最近更新 更多