Spring MVC绑定额外的对象

时间:2013-02-01 17:54:39

标签: spring spring-mvc

我在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也有Useruser由Spring绑定,只要它的属性值也更新。

我将假设这是由于@ModelAttribute个对象中都有BindingResult属性。

我认为在方法签名中UserEditForm表单之后UserEditForm会停止此操作吗?对象是单独的实例,我的表单元素引用<@spring.bind "userEditForm.user.name" /> <input name="${spring.status.expression}" /> 对象:

<input name="user.name" /> 

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

userEditForm.user.name

将名称硬编码为{{1}}会给我带来错误,因此这不是前进的方法。

反正有没有阻止这种情况发生?

1 个答案:

答案 0 :(得分:1)

使用@ModelAttribute注释处理程序方法参数时,这是默认行为。 Spring接受请求属性并将它们与使用@ModelAttribute注释的对象的属性相匹配。这就是Spring在决定做什么时所看到的:你的注释。

由于UserEditFormAdminSession都注明了@ModelAttribute且两者都具有User属性,因此名为user.name的请求属性将绑定到User {1}}属性。

您尝试在输入名称中包含命令名称并出错。那是因为当绑定发生时,它发生在你的命令对象上,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属性,因此不会触发绑定。

这是解决这个问题的一种方法,但这是一种黑客行为。您不希望将请求参数绑定到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
}