SimpleFormController
SimpleFormController - это тот контроллер, который следует использовать если на странице есть формы. Рассмотрим контроллер для регистрации пользователей на сайте. В этом контроллере будут определены основные методы SimpleFormController'a, о которых следует знать. Итак, на форме будут присутствовать поля для ввода имени, пароля, а так же нужно будет выбрать страну, в которой находиться пользователь. Соответствующий бин в Action-servlet.xml выглядит так:
<bean id="registrationController"
class="ru.javatalks.library.viewcontroller.RegistrationController">
<property name="formView" value="registration"/>
<property name="successView" value="home"/>
<property name="commandClass"
value="ru.javatalks.library.viewcontroller.dto.RegistrationDto"/>
<property name="commandName" value="dto"/>
</bean>
По пунктам:
- formView - это как раз тот view, на который будет отправляться пользователь в случае ошибок при вводе или каких-то еще нестандартных ситуаций. В случае регистрации, если пользователь ввел что-то неверно, мы его отправляем обратно на эту же страницу.
- successView - на этот view мы перейдем, если зарегистрируемся успешно. Как правило пользователь переходить на домашнюю страницу в таком случае. Мы не исключение
- commandClass - в данном случае это класс, в поля которого будут заполняться формы. То есть если мы определили форму, на которой есть имя, пароль и страна, потом подсунули обычный POJO с такими же полями, описали на форме какое поле соответствует какому полю в классе, и Spring MVC сам заполнит эти поля в бин. Обычно объекты, в которые заполняются данными для передачи куда-либо, называются DTO(Data Transfer Object).
- commandName - это название объекта на странице. То есть для того, чтоб обратиться к полям нашего DTO, мы должны дать ему имя - идентификатор объекта на странице. Аналогично, если мы сервлетом передали какой-то объект в request, то на странице мы сможем обратиться по его имени через EL: ${objectName.field}. Подобные принципы использует и Spring MVC для обращению к command object на странице.
Так выглядит этот пресловутый DTO:
package ru.javatalks.library.viewcontroller.dto;
/**
* 27.12.2009 10:50:24
*
* @author ctapobep
*/
public class RegistrationDto {
private String username;
private String password;
private String country;
public RegistrationDto() {
}
public RegistrationDto(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
А вот код самого контроллера:
package ru.javatalks.library.viewcontroller;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import ru.javatalks.library.viewcontroller.dto.RegistrationDto;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
/**
* 27.12.2009 10:42:04
*
* @author ctapobep
*/
public class RegistrationController extends SimpleFormController {
@Override
protected Object formBackingObject(HttpServletRequest httpServletRequest) throws Exception {
return new RegistrationDto();
}
@Override
protected Map referenceData(HttpServletRequest httpServletRequest) throws Exception {
Map<String, Object> attributes = new HashMap<String, Object>(1);
attributes.put("countries", getAllCountries());
return attributes;
}
@Override
protected ModelAndView onSubmit(Object command, BindException e) throws Exception {
RegistrationDto dto = (RegistrationDto) command;
ModelAndView mv = new ModelAndView(getSuccessView());
mv.addObject("username", dto.getUsername());
mv.addObject("country", dto.getCountry());
return mv;
}
public Map<String, String> getAllCountries() {
Map<String, String> map = new TreeMap<String, String>();
Locale.setDefault(new Locale("en"));
Locale[] locales = Locale.getAvailableLocales();
for (int i = 0; i < locales.length; i++) {
String country = locales[i].getDisplayCountry();
map.put(country, country);
}
return map;
}
}
Опять же по пунктам:
- formBackgingObject() - этот метод, если его не переопределять, возвращает новый объект нашего RegistrationDto класса. Поэтому этот класс должен обязательно иметь конструктор по умолчанию - без параметров. В данном случае мы тоже создаем просто новый объект - это сделано чисто для того, чтоб показать, что этот метод есть. Мы б могли, кстати, заполнить этот объект какими-то значениями по умолчанию, тогда на форме сразу появятся эти значения в полях ввода.
- referenceData() - метод, который возвращает какие-то дополнительные, как правило статические, данные, которые нужно показать пользователю сразу. В данном случае мы возвращает список стран, чтоб он мог выбрать одну из них в выпадающем списке (на самом деле этот способ не вернет все страны мира, в реальных приложениях эти значения должны храниться где-то в БД). Так вот, карта, возвращаемая данным методом, помещается в атрибуты request, то есть к этим объектам, что находятся в Map, можно обращаться с помощью обычного EL.
- onSubmit() - выполняется когда пользователь делает submit формы. Здесь мы, кстати, сталкиваемся вновь с нашим ModelAndView. Помните мы установили значение для successView - в конструктор, как видите, мы передаем этот view в конструктор. После этого, выполнение переходит на successView.
Теперь вы увидите страницу нашей регистрации. Не печальтесь, если увидите там незнакомые теги, мы их все рассмотрим позже, пока интуитивно вы должны понимать приблизительный смысл:
registration.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head><title>Registration</title></head>
<body>
<form:form commandName="dto">
<form:input path="username"/>
<form:password path="password"/>
<form:select path="country">
<form:options items="${countries}"/>
</form:select>
<input type="submit">
</form:form>
</body>
</html>
А вот home.jsp, на которую мы переходим после submit регистрации:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Simple jsp page</title></head>
<body><c:out value="${username}"/>
<br><c:out value="${country}"/></body>
</html>
Если захотите уже сейчас попробовать самостоятельно запустить приложение, то увидите после submit'a регистрации эту home-страницу с теми значениями, что вы вводили. Если кто не догадался, Action-servlet.xml теперь будет содержать следующие строки:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean name="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/index.form">indexController</prop>
<prop key="/registration.form">registrationController</prop>
</props>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/pages/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="indexController" class="ru.javatalks.library.viewcontroller.IndexController">
<property name="view" value="index"/>
</bean>
<bean id="registrationController"
class="ru.javatalks.library.viewcontroller.RegistrationController">
<property name="formView" value="registration"/>
<property name="successView" value="home"/>
<property name="commandClass"
value="ru.javatalks.library.viewcontroller.dto.RegistrationDto"/>
<property name="commandName" value="dto"/>
</bean>
</beans>
Однако имейте в виду, что просто перейти на страницу home не выйдет, т.к. мы не определили ни URL для нее, ни контроллер.