在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()方法。

这里所ServletModelAttributeMethodProcessorHandlerMethodArgumentResolver实现是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到模型属性对象上,并使用其字段创buildinputlabel元素。 只要这个对象如何在模型中结束,并不重要。 如果它找不到具有指定名称(键)的模型属性,则会抛出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属性将请求参数绑定到实例字段。