2013-09-22 5 views
30

У меня возникли проблемы с пониманием того, как форма представляет в Spring 3 MVC работу.Форма отправить в Spring MVC 3 - описание

Что я хочу сделать, это создать контроллер, который будет принимать имя пользователя и отображать его для него. И как-то я это сделал, но я действительно не понимаю, как это работает. Так ..

У меня есть форма, которая выглядит следующим образом:

<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> 

И он работает (я опускаю файлы конфигурации XML, поскольку они ar e не имеет отношения к проблеме).

Я думал, что атрибут «modelAttribute» в форме указывает на переменную bean, которая должна быть заполнена значениями входов (как указано в их атрибутах «путь»). Но выглядит, работает совсем по-другому. Если удалить строку

model.addAttribute("person", new Person()); 

от метода «showHelloPage» я получаю (общее) исключение «Ни BindingResult, ни ...».

Кроме того, в начале, метод "SayHello" выглядел так:

(...) 
public String sayHello(@ModelAttribute("person") Person person, Model model) { 
(...) 

Я имею в виду, это было "ModelAttribute" аннотация. Я добавил это, потому что в учебниках, которые я прочитал, он всегда присутствовал. Но после того, как я удалил его, все прошло хорошо, как и раньше.

Так что мой вопрос: - Какая польза от аннетации «ModelAttribute»? Можно ли опустить атрибут «modelAttribute» в форме? И вторая часть, каков способ (возможно, некоторая аннотация) для создания формы, автоматически связывает значения входов с собственными свойствами bean (которые будут объявлены как параметр метода)? Без необходимости добавления пустого компонента перед отправкой формы (как я должен сделать это сейчас).

Спасибо за ваши ответы (которые не являются ссылками на документацию Spring, потому что я ее уже прочитал).

ответ

38

Аннотации @ModelAttribute в этом случае используются для идентификации объекта, который Spring должен добавить в качестве атрибута модели. Атрибуты модели - это абстракция от атрибутов HttpServletRequest. В основном, это объекты, определенные некоторым ключом, которые найдут свой путь в атрибутах HttpServletRequest. Вы можете сделать это, вручную добавив атрибут с Model#addAttribute(String, Object), используйте аннотированный метод @ModelAttribute или аннотируя параметр метода с помощью @ModelAttribute.

Что нужно понять, так это то, как Spring разрешает параметры метода обработчика и вводит аргументы. Для этого используется интерфейс HandlerMethodArgumentResolver. Существует несколько классов реализации (см. Javadoc), и каждый из них несет ответственность за resolveArgument(), возвращая аргумент, который Spring будет использовать для метода вашего обработчика с помощью рефлексии invoke().Spring вызовет только метод resolveArgument(), если метод HandlerMethodArgumentResolversupportsParameter() возвращает true для конкретного параметра.

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; 
} 

Когда весна должна вызывать ваш метод обработки, он будет перебирать типов параметров и через приведенный выше список и использовать первый это 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()); 

необходимо с <form> TagLib. Вот как он разрешает свои поля input.


Так что мой вопрос - что такое использование "ModelAttribute" anonnatation?

Чтобы автоматически добавить указанный параметр (или возвращаемое значение метода) в модель.

Можно ли опустить атрибут «modelAttribute» в форме?

Нет, form вяжущие выглядит для объекта в Model и связывает свои поля HTML input элементов.

И вторая часть, что путь (возможно, некоторые аннотаций), чтобы сделать формы автоматически связывать значения INPUTs' свойствам надлежащего бин (который был бы объявлен как параметр методы)? Без необходимости добавлять пустой bean-компонент перед отправкой формы (как я должен сделать это сейчас).

Весеннее <form> тег впивается модель атрибутов объекта и использует свои поля для создания input и label элементов. Неважно, как объект оказался в модели до тех пор, пока он это сделал. Если он не может найти атрибут модели с указанным вами именем (ключом), он выдает исключения, как вы видели.

<form:form method="post" modelAttribute="person"> 

Альтернативой предоставлению пустого компонента является создание html самостоятельно. Все Spring <form> does использует имена полей 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.

+0

Большое спасибо за ваш ответ, вы мне многое объяснили. Еще один вопрос об аннотации «ModelAttribute» - если я правильно вас понимаю, эта аннотация, используемая с параметром метода, эквивалентна «model.addAttribute (...)»? –

+0

@ MichałTabor Попробуйте добавить его как параметр метода. Я не уверен, если, поскольку запрос не имеет параметров запроса, которые могут быть связаны, он вернет 'null'. В противном случае, как вы это делаете, это правильный путь. Они называются объектами передачи данных (или объектами резервного копирования Spring или объектами команд). Документация должна содержать более подробную информацию. –

+0

+1, отличное объяснение – rocketboy

Смежные вопросы