1

我在 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它也User被 Spring 绑定,因为它的属性值也被更新。

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

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

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

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

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

<input name="user.name" /> 

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

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

4

1 回答 1

1

这是使用@ModelAttribute. Spring 获取请求属性并将它们与带有注释的对象的属性匹配@ModelAttribute。这就是 Spring 在决定做什么时所关注的:您的注释。

由于UserEditFormAdminSession都被注释了@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属性,因此不会触发绑定。

这是解决这个问题的一种方法,但它是一种黑客行为。您不希望将请求参数绑定到,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
}
于 2013-02-03T11:11:49.337 回答