本例中的@ModelAttribute 注释用于标识Spring 应添加为模型属性的对象。模型属性是HttpServletRequest 属性的抽象。基本上,它们是由某个键标识的对象,这些键将进入HttpServletRequest 属性。您可以通过使用Model#addAttribute(String, Object) 手动添加属性、使用@ModelAttribute 注释方法或使用@ModelAttribute 注释方法参数来完成此操作。
您需要了解的是 Spring 如何解析您的处理程序方法参数并注入参数。它使用HandlerMethodArgumentResolver 接口来执行此操作。有许多实现类(参见 javadoc),每个类都对 resolveArgument() 负责,通过反射将 Spring 将使用的参数返回给 invoke() 您的处理程序方法。如果HandlerMethodArgumentResolver supportsParameter() 方法为特定参数返回true,Spring 只会调用resolveArgument() 方法。
这里有问题的HandlerMethodArgumentResolver 实现是ServletModelAttributeMethodProcessor,它从ModelAttributeMethodProcessor 扩展而来
解析使用@ModelAttribute 注释的方法参数和句柄
从带有 @ModelAttribute 注释的方法返回值。
Spring (3.2) 将register 这个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 需要调用你的处理方法时,它会遍历参数类型和上面的列表,并使用supportsParameter() 的第一个。
请注意,添加了两个ServletModelAttributeMethodProcessor 实例(一个在//catch all 注释之后)。 ModelAttributeMethodProcessor 有一个 annotationNotRequired 字段,它告诉它是否应该查找 @ModelAttribute。第一个实例必须查找@ModelAttribute,第二个则不需要。 Spring 这样做是为了让您可以注册自己的 HandlerMethodArgumentResolver 实例,请参阅 // Custom arguments 评论。
具体
@RequestMapping(value = "/", method = RequestMethod.POST)
public String sayHello(Person person, Model model) {
model.addAttribute("person", person);
return "home";
}
在这种情况下,您的Person 参数是否被注释并不重要。 ModelAttributeMethodProcessor 将解决它并绑定表单字段,即。请求参数,到实例的字段。您甚至不需要将其添加到 model,因为 ModelAttributeMethodProcessor 类会处理它。
在您的showHelloPage() 方法中
model.addAttribute("person", new Person());
<form> 标签库需要
。这就是它解析其input 字段的方式。
所以我的问题是 - “ModelAttribute”的用途是什么
注释?
将指定的参数(或方法返回值)自动添加到模型中。
有没有办法在表单中省略“modelAttribute”属性?
不,form 绑定在 Model 中查找对象并将其字段绑定到 html input 元素。
第二部分是什么方法(可能是一些注释)
表单自动将输入的值绑定到正确的 bean 的属性
(这将被声明为方法参数)?无需添加
发送表单之前的空 bean(我现在必须这样做)。
Spring <form> 标记锁定模型属性对象并使用其字段创建 input 和 label 元素。只要对象最终出现在模型中,它并不重要。如果它找不到具有您指定的名称(键)的模型属性,它会抛出异常,如您所见。
<form:form method="post" modelAttribute="person">
提供空 bean 的替代方法是自己创建 html。所有 Spring 的 <form> 所做的只是使用 bean 的字段名称来创建一个 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 属性将请求参数绑定到实例字段。