【问题标题】:Spring MVC binding extra objectsSpring MVC 绑定额外对象
【发布时间】:2013-01-17 02:44:39
【问题描述】:

我在 Spring MVC 3 中遇到了一些奇怪的绑定问题。

我的控制器请求映射如下所示:

@RequestMapping
public String save(HttpServletRequest req, 
           @ModelAttribute("userEditForm") UserEditForm form, 
           BindingResult formBindingResult, 
           ModelMap model, 
           @ModelAttribute("session") AdminSession session) {
    // some validation etc
}

UserEditForm:

public class UserEditForm {
    private User user;
    public User getUser() { ... }
    public void setUser(User user) { ... }
}

AdminSession:

public class AdminSession {
    private User user;
    public User getUser() { ... }
    public void setUser() { ...}
}

发生的情况是,当我提交表单时,Spring 正在绑定 User,正如我在 UserEditForm 对象中所期望的那样,但是,到目前为止,AdminSession 也被 Spring 绑定了 User因为它的属性值也会更新。

我假设这是由于在两个 @ModelAttribute 对象中都有一个 user 属性。

我认为在方法签名中的UserEditForm 表单之后添加BindingResult 会阻止这种情况吗?这些对象是单独的实例,我的表单元素引用了UserEditForm 对象:

<@spring.bind "userEditForm.user.name" />

<input name="${spring.status.expression}" />

我注意到它在生成的 HTML 中输出:

<input name="user.name" /> 

将名称硬编码为 userEditForm.user.name 会给我错误,所以这不是前进的方向。

有没有办法阻止这种情况发生?

【问题讨论】:

  • 如果您要对名称进行硬编码,我认为您必须使用完全限定名称,从模型属性名称开始。因此,在您的示例中,我希望

标签: spring spring-mvc


【解决方案1】:

这是使用@ModelAttribute 注释处理程序方法参数时的默认行为。 Spring 获取请求属性并将它们与带有@ModelAttribute 注释的对象的属性相匹配。这就是 Spring 在决定做什么时所关注的:您的注释。

由于UserEditForm 和AdminSession 都使用@ModelAttribute 进行注释并且都具有User 属性,因此名为user.name 的请求属性将绑定到User 属性。

您尝试在输入名称中包含命令名称,但出现错误。这是因为当绑定发生时,它发生在您的命令对象上,Spring 会在其上查找属性(bindinf 路径是相对于命令对象的),当然表达式找不到任何具有该名称的属性。如果您想使用全名,您可以将表单包装在另一个对象中并将其用于您的命令,如下所示:

public class UserEditFormWrapper {
    private UserEditForm form;
    public UserEditForm getForm() {
        return form;
    }
    public void setForm(UserEditForm form) {
        this.form = form;
    }
}

现在您可以在输入中使用这样的表达式:form.user.name,当您提交到您的处理程序方法时,现在看起来像这样:

@RequestMapping
public String save(HttpServletRequest req, 
        @ModelAttribute("userEditForm") UserEditFormWrapper formWrapper, 
        BindingResult formBindingResult, 
        ModelMap model, 
        @ModelAttribute("session") AdminSession session) {

    UserEditForm form = formWrapper.getForm();
    // some validation etc
}

不会触发绑定,因为AdminSession 没有form 属性。

这是解决此问题的一种方法,但它是一种 hack。您不希望将请求参数绑定到AdminSession,但这是您模型的一部分,因此您必须在某处创建它并将其放置在模型上,对吗?如果是这样,则将其从方法的参数中删除并从模型中获取,例如:

@RequestMapping(value = "/test", method = { RequestMethod.POST })
public String handlePost(HttpServletRequest req, 
        @ModelAttribute("userEditForm") UserEditForm form, 
        BindingResult formBindingResult, ModelMap model) {

    AdminSession session = (AdminSession) model.get("session");
    // some validation etc
}

【讨论】:

  • 谢谢博格丹,我想知道这是否是答案。很好的解释,现在对我来说一切都有意义!
猜你喜欢
  • 2014-05-08
  • 1970-01-01
  • 2012-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-29
  • 1970-01-01
  • 2011-04-09
相关资源
最近更新 更多