Spring-SimpleFormController
- 按请求转到相应controller;
- 调用formBackingObject()方法,创建一个command对象的实例(如果设定了commandClass,则不需要override formBackingObject()方法了);
- 调用initBinder(),注册需要的类型转换器;
- 调用showForm()方法,返回一个view,即准备呈现给用户的视图,一般情况下这个方法是不需要override的,只需设定formView即可;
- 调用referenceData()方法。这个方法返回一个Map对象,可以把在view中需要展现的数据放入这个Map中;
- 转到formView指定的视图。
一般情况下步骤2,3,4的方法是不需要override的,它们只需要在配置文件中进行相关属性的定义即可。而步骤5的referenceData()一般是要在自己的SimpleFormController中进行重新定义的。
post方法处理流程(一般用于处理表单):
- 按请求转到相应controller;
- 调用formBackingObject()方法,创建一个command对象的实例(如果设定了commandClass,则不需要override formBackingObject()方法了);
- 把请求参数注入表单对象;
- 执行onBind()方法;
- 执行validator验证。
- 执行onBindAndValidate()方法;
- 若有err,则转到formView视图;
- 执行onSubmit()方法或doSubmitAction()方法。
- onSubmit(req, res, command, errs);
- onSubmit(command, errs);
- onSubmit(command);
但是这三种方法不是孤立的,第一个方法在执行中会调用第二个方法,第二个方法在执行中会调用第三个方法。一般在定义自己的SimpleFormController时只是override onSubmit(command)方法。
doSubmitAction()方法是一个有意思的方法,它的完整定义如下:
protected void doSubmitAction(Object obj) throws Exception |
它的返回类型是void,而不是我们预想的ModelAndView,并且也不返回任何视图层需要的数据。实际上doSubmitAction执行完毕后会自动转到successView视图。并且如果配合sessionForm来使用的的话(sessionForm设为true),那么在转到successView视图后,在session中可以取到先前的表单对象(所谓的POJO)。
说了这么多,还是看个实例比较形象(SimpleFormController(中))。
下面是一个SimpleFormController的实例,虽然有些地方显得吹毛求疵,但主要是为了表达一个完整的流程。
/WEB-INF/mvc-config.xml:
<?xml version=”1.0″ encoding=”UTF-8″?> <!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd“> <beans> <!–InternalResourceViewResolver–> <bean id=”viewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”> <property name=”prefix”> <value>/WEB-INF/jsp/</value> </property> <property name=”suffix”> <value>.jsp</value> </property> </bean> <!–SimpleUrlHandlerMapping–> |
然后是/WEB-INF/controller-config.xml:
<?xml version=”1.0″ encoding=”UTF-8″?> <!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd“> <beans> <bean id=”userValidator” class=”com.yangsq.validator.UserValidator”/> <bean id=”userController” |
这里需要对上面的配置文件进行说明。commandName属性的设置是为了可以在页面中使用Spring tag,对业务流程没有影响,如果不想使用Spring tag,则这个属性可以没有。commandClass指定了封装表单的类,注意,要指定完整的路径,不能只指定一个类名,也不能<ref …/>。validator的设定说明了要使用验证器。formView和successView这两个属性设定了转向的页面,它们是父类所具有的,所以不需要在你的controller中再注入了。
import org.springframework.validation.Errors; import com.yangsq.domain.User; public class UserValidator implements Validator{ public boolean supports(Class clazz) { public void validate(Object obj, Errors err) { |
验证器实现了Validator借口,supports和validate这两个方法是必须实现的。验证器的主要任务是对表单类进行验证,这时请求的数据已经封装到表单类里了。
下面是表单类:
public class User { private String account; private String phone; private int age; private String city; private Date createTime; public String getAccount() { |
属性包括用户名称,电话,年龄,城市和创建日期。此外,为了表达一个完成的演示,还创建了一个city类:
public class City { private String cityName; private String cityNo; public String getCityName() { return cityName; } public void setCityName(String cityName) { this.cityName = cityName; } public String getCityNo() { return cityNo; } public void setCityNo(String cityNo) { this.cityNo = cityNo; } } |
下面就是这个例子的主角,UserController:
public class UserController extends SimpleFormController { protected Map referenceData(HttpServletRequest req) throws Exception { List cityList = new ArrayList(); map.put(“cityList”, cityList); protected void onBind(HttpServletRequest req, Object obj) throws Exception { protected void onBindAndValidate(HttpServletRequest req, Object obj, BindException err) throws Exception { protected ModelAndView onSubmit(Object obj) throws Exception { |
下面是使用到的页面 user.jsp的主要部分(表单):
<FORM action=”user.htm” method=”post”> <TABLE> <TBODY> <TR> <TD> <spring:bind path=”command.account”> 用户名:<INPUT name=”${status.expression}” type=”text” value=”${status.value}”/> </spring:bind> </TD> </TR> <TR> <TD> <spring:bind path=”command.age”> 年龄:<INPUT name=”${status.expression}” type=”text” value=”${status.value}”/> </spring:bind> </TD> </TR> <TR> <TD> <spring:bind path=”command.phone”> 电话号码:<INPUT name=”${status.expression}” type=”text” value=”${status.value}”/> </spring:bind> </TD> </TR> <TR> <TD> <spring:bind path=”command.city”> 城市: <SELECT name=”${status.expression}”> <c:forEach items=”${cityList}” var=”city” varStatus=”loopStep”> <OPTION value=”${city.cityNo}” <c:if test=”${city.cityNo == status.value}”>selected</c:if>> <c:out value=”${city.cityName}”/> </OPTION> </c:forEach> </SELECT> </spring:bind> </TD> </TR> <TR> <TD> <spring:bind path=”command.*”> <c:out value=”${status.errorMessage}”/> </spring:bind> </TD> </TR> <TR> <TD align=”center”> <INPUT type=”submit” value=”提交” /> </TD> </TR> </TBODY> </TABLE> </FORM> |
hello.jsp的主要部分:
<TABLE> <TBODY> <TR> <TD> User infor: </TD> </TR> <TR> <TD> <c:out value=”${user.account}” /> </TD> </TR> <TR> <TD> <c:out value=”${user.age}” /> </TD> </TR> <TR> <TD> <c:out value=”${user.phone}” /> </TD> </TR> <TR> <TD> <c:out value=”${user.city}” /> </TD> </TR> <TR> <TD> <c:out value=”${user.createTime}” /> </TD> </TR> </TBODY> </TABLE> |
在 SimpleFormController(下)会结合效果图,说明一下整个流程:
在地址栏中直接输入地址
http://localhost:8080/SpringMVC/user.htm(SpringMVC是工程名),会显示如下页面(user.jsp):
SimpleFormController(上)里介绍了SimpleFormController对get方法的处理流程。这里会执行UserController的referenceData方法。在referenceData方法里生成了一个城市类的List。用于user.jsp(formView)的城市下来框。
SimpleFormController(上)里介绍了SimpleFormController对post方法的处理流程。在UserController里,首先会执行onBind方法,然后是UserValidator类(验证器),然后是onBindAndValidate方法。由于UserValidator类检验出了错误(电话号码位数不够),所以执行完onBindAndValidate方法后会转到user.jsp(formView)。而不会执行onSubmit方法。
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/13588.html