Ответ 1
В этом случае аннотация @ModelAttribute
используется для идентификации объекта, который Spring должен добавить как атрибут модели. Атрибуты модели - это абстракция от атрибутов HttpServletRequest
. В основном, это объекты, идентифицированные некоторым ключом, которые найдут свой путь в атрибутах HttpServletRequest
. Вы можете сделать это, вручную добавив атрибут с помощью Model#addAttribute(String, Object)
, иметь аннотированный метод @ModelAttribute
или аннотировать параметр метода с помощью @ModelAttribute
.
То, что вам нужно понять, это то, как Spring разрешает параметры метода обработчика и вводит аргументы. Для этого используется интерфейс HandlerMethodArgumentResolver
. Существует несколько классов реализации (см. Javadoc), и каждый из них несет ответственность за resolveArgument()
, возвращая аргумент, который Spring будет использовать для invoke()
вашего метода обработчика посредством отражения. Spring вызовет только метод resolveArgument()
, если метод HandlerMethodArgumentResolver
supportsParameter()
возвращает true
для конкретного параметра.
Реализация HandlerMethodArgumentResolver
, о которой идет речь, здесь ServletModelAttributeMethodProcessor
, которая простирается от ModelAttributeMethodProcessor
, в котором указано
Разрешает аргументы метода, аннотированные с помощью @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 должен вызвать метод обработчика, он будет перебирать типы параметров и через приведенный выше список и использовать первый, который 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
или нет. A ModelAttributeMethodProcessor
разрешит его и свяжет поля формы, т.е. параметры запроса, в поля экземпляра. Вам даже не нужно добавлять его в model
, поскольку класс ModelAttributeMethodProcessor
будет обрабатывать это.
В вашем методе showHelloPage()
model.addAttribute("person", new Person());
необходим с taglib <form>
. То, как он разрешает свои поля input
.
Итак, мой вопрос: что такое "ModelAttribute", anonnatation?
Чтобы автоматически добавить указанный параметр (или возвращаемое значение метода) в модель.
Можно ли опустить атрибут "modelAttribute" в форме?
Нет, привязка form
ищет объект в model
и связывает его поля с элементами html input
.
И вторая часть, каков способ (возможно, аннотация), чтобы сделать форма автоматически привязывает значения входных данных к соответствующим свойствам bean(который будет объявлен как параметр метода)? Без необходимости добавления пустой bean перед отправкой формы (как я должен сделать это сейчас).
A 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
.