Добрый день!
Для тех, кто работал со Spring MVC ни для кого не секрет, что Spring имеет свою собственную библиотеку тегов. Об одном из этих тегов и будет мой вопрос. А именно о теге "form:form", а вернее о его атрибуте modelAttribute (аналог устаревшего commandName).
Читая документацию, я сначала подумал что этот атрибут используется только для того, чтобы заполнить форму какими-то начальными данными (т.е. основа для формы, backing object). И только для этого, ни для чего более.
Но в процессе работы выяснилось, что этот атрибут, также определяет объект, который будет отправлен данной формой и будет получен в контроллере. Но как это происходит? За счет чего? Посредством чего? За счет какого механизма? Ведь, насколько мне известно, HTML-запросы не могут передавать объекты - они могут передавать параметры запроса, но никак не объекты.
Если вопрос не понятен, то опишу подробности. Если понятен, то дальше можно не читать.
На всякий случай код контроллера:
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView main() {
User user = new User();
return new ModelAndView("index", "userObj", user);
}
@RequestMapping(value = "/check-user", method = RequestMethod.POST)
public String checkUser(@Valid @ModelAttribute(name = "userObj") User user, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) return "index";
return "check-user";
}
А это код формы:
<form:form class="box login" modelAttribute="userObj" method="POST" action="check-user">
<fieldset class="boxBody">
<label>Username</label>
<form:input path="name"/>
<form:errors path="name" cssClass="error" />
<label>Password</label>
<form:password path="password"/>
<form:errors path="password" cssClass="error"/>
</fieldset>
<footer>
<form:checkbox path="admin" />
<label>Admin?</label>
<input type="submit" class="btnLogin" value="Login" tabindex="4">
</footer>
</form:form>
Ход мыслей:
При запросе на "/" в атрибут модели помещается объект userObj (что практически эквивалентно добавлению атрибута запроса в не Spring MVC приложении, т.е. атрибут модели userObj будет доступен только в рамках одного запроса) и отдается представление index - на нем располагается форма.
Сервер отдает страницу с формой. Поскольку useObj пустой, то форма отрендерится с пустыми значениями полей. Запрос завершается, атрибут модели userObj больше не доступен. Заполняем поля формы значениями и нажимаем submit. Начинается новый запрос. Данные уходят в обработчик checkUser().
В сигнатуре checkUser():
public String checkUser(@Valid @ModelAttribute(name = "userObj") User user, BindingResult bindingResult, Model model)
видно, что мы извлекаем из модели атрибут userObj и помещаем его в переменную User user. Но как? Ведь это уже другой запрос и прошлый атрибут userObj (который был пустым) уже утерян!
Остается только предположить, что форма каким-то образом генерирует новый атрибут модели, в который помещает заполненный объект user. Но как это происходит технически? Ведь как я уже написал, запрос клиента не может передать атрибут модели (он может передавать только параметры запроса - введенные данные в поля формы). И происходит это генерирование, видимо, за счет атрибута modelAttribute (устар. commandName).
Получается что у сервера уже откуда-то есть информация о том, что атрибут должен быть именно "userObj". Если в контроллере попытаться получить атрибут с другим именем, например, "useObj2" то будет брошено исключение. Каким образом передается от клиента серверу информация об атрибуте модели и о его имени? Посредством чего modelAttribute (устар. commandName) из JSP формы передает атрибут в модель? Может за счет id формы (в которую в конечном счете отрендериться Spring-форма и modelAttribute станет видимо id'шником)? Или как?
Факт остается фактом, получить в контроллере введенные данные можно только указав значение modelAttribute (устар. commandName). В теле POST-запроса, передаваемого от клиента, есть информация о введенных данных, но нет и быть не может об атрибуте модели. Но откуда-то сервер знает имя нужного атрибута?
С уважением, надеюсь понятно написал.