在Spring MVC 3中提交表单 – 解释
我在理解如何在Spring 3 MVC工作中提交表单。
我想要做的是创build一个控制器,将用户名和显示给他。 不知何故,我已经做到了,但我真的不明白它是如何工作的。 所以..
我有一个这样的表格:
<form:form method="post" modelAttribute="person"> <form:label path="firstName">First name</form:label> <form:input path="firstName" /> <br /> <form:label path="lastName">Last name</form:label> <form:input path="lastName" /> <br /> <input type="submit" value="Submit" /> </form:form>
我也有一个这样的控制器:
@Controller public class HomeController { @RequestMapping(value = "/", method = RequestMethod.GET) public String showHelloPage(Model model) { model.addAttribute("person", new Person()); return "home"; } @RequestMapping(value = "/", method = RequestMethod.POST) public String sayHello(Person person, Model model) { model.addAttribute("person", person); return "home"; } }
要向用户显示欢迎消息我在JSP页面中使用以下代码:
<c:if test="${not empty person.firstName and not empty person.lastName}"> Hello ${person.firstName} ${person.lastName}! </c:if>
它有效(我省略了XMLconfiguration文件,因为它们与问题无关)。
我认为表单中的“modelAttribute”属性指向了应该用input值填充的beanvariables(如在其“path”属性中设置的)。 但看起来,它的工作方式非常不同。 如果我删除线
model.addAttribute("person", new Person());
从“showHelloPage”方法我得到一个(共同)exception“既不BindingResult也不…”。
另外,一开始,“sayHello”方法看起来像:
(...) public String sayHello(@ModelAttribute("person") Person person, Model model) { (...)
我的意思是,它有“ModelAttribute”注释。 我补充说,因为在我读过的教程中,它总是存在的。 但是在我删除它之后,一切都运行良好,就像以前一样。
所以我的问题是 – “ModelAttribute”anonnatation的用法是什么? 是否有一种方法可以省略表单中的“modelAttribute”属性? 第二部分,创build表单的方式(可能是某些注释)自动将input的值绑定到适当的bean的属性(将被声明为方法参数)? 在发送表单之前不需要添加空的bean(因为我现在必须这样做)。
感谢您的回复(这不是Spring文档的链接,因为我已经阅读过)。
在这种情况下,@ @ModelAttribute
注释用于标识Spring应添加为模型属性的对象。 模型属性是HttpServletRequest
属性的抽象。 基本上,它们是通过一些可以进入HttpServletRequest
属性的键来标识的对象。 您可以通过手动添加Model#addAttribute(String, Object)
的属性, @ModelAttribute
注释的方法或@ModelAttribute
注释方法参数来实现此目的。
您需要了解的是Spring如何parsing您的处理程序方法参数并注入参数。 它使用HandlerMethodArgumentResolver
接口来执行此操作。 有许多实现类(请参阅javadoc),每个类都有责任通过返回Spring将通过reflectioninvoke()
您的处理程序方法的参数来resolveArgument()
。 如果HandlerMethodArgumentResolver
supportsParameter()
方法对特定参数返回true
,Spring将只调用resolveArgument()
方法。
这里所ServletModelAttributeMethodProcessor
的HandlerMethodArgumentResolver
实现是ServletModelAttributeMethodProcessor
,它从ModelAttributeMethodProcessor
parsing用@ModelAttribute注解的方法参数,并处理来自用@ModelAttribute注释的方法的返回值。
Spring(3.2)将注册这个HandlerMethodArgumentResolver
等
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); // Annotation-based argument resolution resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters())); resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters())); resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); // Type-based argument resolution resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(getMessageConverters())); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // Custom arguments if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); } // Catch-all resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers; }
当Spring需要调用你的处理程序方法时,它将遍历参数types和上面的列表,并使用第一个supportsParameter()
。
请注意,添加了两个ServletModelAttributeMethodProcessor
实例( //catch all
注释之后)。 ModelAttributeMethodProcessor
有一个annotationNotRequired
字段,告诉它它是否应该查找@ModelAttribute
或不。 第一个实例必须寻找@ModelAttribute
,第二个不是。 Spring HandlerMethodArgumentResolver
,以便您可以注册您自己的HandlerMethodArgumentResolver
实例,请参阅// Custom arguments
注释。
特别
@RequestMapping(value = "/", method = RequestMethod.POST) public String sayHello(Person person, Model model) { model.addAttribute("person", person); return "home"; }
在这种情况下,你的Person
参数是否被注释并不重要。 ModelAttributeMethodProcessor
将parsing它并绑定表单域,即。 请求参数,到实例的字段。 您甚至不需要将其添加到model
因为ModelAttributeMethodProcessor
类将处理该模型。
在你的showHelloPage()
方法中
model.addAttribute("person", new Person());
是需要与<form>
taglib。 这就是它如何解决其input
字段。
所以我的问题是 – “ModelAttribute”anonnatation的使用是什么?
自动将指定的参数(或方法返回值)添加到模型。
是否有一种方法可以省略表单中的“modelAttribute”属性?
不, form
绑定在Model
查找一个对象,并将其字段绑定到html input
元素。
第二部分,创build表单的方式(可能是某些注释)自动将input的值绑定到适当的bean的属性(将被声明为方法参数)? 在发送表单之前不需要添加空的bean(因为我现在必须这样做)。
Spring <form>
标签locking到模型属性对象上,并使用其字段创buildinput
和label
元素。 只要这个对象如何在模型中结束,并不重要。 如果它找不到具有指定名称(键)的模型属性,则会抛出exception,如您所见。
<form:form method="post" modelAttribute="person">
提供一个空bean的替代方法是自己创buildhtml。 所有Spring的<form>
都是使用bean的字段名称来创build一个input
元素。 所以这
<form:form method="post" modelAttribute="person"> <form:label path="firstName">First name</form:label> <form:input path="firstName" />
创造类似的东西
<form method="post" action="[some action url]"> <label for="firstName">First name<label> <input type="text" name="firstName" value="[whatever value firstName field had]" /> ...
Spring使用name
属性将请求参数绑定到实例字段。