我在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
。user
由Spring绑定,只要它的属性值也更新。
我将假设这是由于@ModelAttribute
个对象中都有BindingResult
属性。
我认为在方法签名中UserEditForm
表单之后UserEditForm
会停止此操作吗?对象是单独的实例,我的表单元素引用<@spring.bind "userEditForm.user.name" />
<input name="${spring.status.expression}" />
对象:
<input name="user.name" />
我注意到在生成的HTML中它正在输出:
userEditForm.user.name
将名称硬编码为{{1}}会给我带来错误,因此这不是前进的方法。
反正有没有阻止这种情况发生?
答案 0 :(得分:1)
使用@ModelAttribute
注释处理程序方法参数时,这是默认行为。 Spring接受请求属性并将它们与使用@ModelAttribute
注释的对象的属性相匹配。这就是Spring在决定做什么时所看到的:你的注释。
由于UserEditForm
和AdminSession
都注明了@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
}