Spring-SimpleFormController 我不是女神ヾ 2022-08-07 08:38 142阅读 0赞 ## Spring-SimpleFormController ## SimpleFormController在Controller继承体系位于最底端,是一个功能强大,而且比较复杂的Controller。下面是SimpleFormController的主要继承图谱: [![Spring学习笔记(十二)----SimpleFormController(上)][Spring_----SimpleFormController]][Spring_----SimpleFormController_Spring_----SimpleFormController] (摘自 [http://www.javaworld.com.tw/jute/post/view?bid=42&id=152356][http_www.javaworld.com.tw_jute_post_view_bid_42_id_152356]) SimpleFormController本身的强大和复杂性从上图就可以看出。实际上,SimpleController除了在处理上要经过一个多步的流程,而且在处理不同类型请求时(如post,get)。(希望大家看一下上面的图和bean定义) 下面是SimpleFormController的处理流程,分为post方法和get方法。 get方法处理流程(一般连接的形式为get方法): 1. 按请求转到相应controller; 2. 调用formBackingObject()方法,创建一个command对象的实例(如果设定了commandClass,则不需要override formBackingObject()方法了); 3. 调用initBinder(),注册需要的类型转换器; 4. 调用showForm()方法,返回一个view,即准备呈现给用户的视图,一般情况下这个方法是不需要override的,只需设定formView即可; 5. 调用referenceData()方法。这个方法返回一个Map对象,可以把在view中需要展现的数据放入这个Map中; 6. 转到formView指定的视图。 一般情况下步骤2,3,4的方法是不需要override的,它们只需要在配置文件中进行相关属性的定义即可。而步骤5的referenceData()一般是要在自己的SimpleFormController中进行重新定义的。 post方法处理流程(一般用于处理表单): 1. 按请求转到相应controller; 2. 调用formBackingObject()方法,创建一个command对象的实例(如果设定了commandClass,则不需要override formBackingObject()方法了); 3. 把请求参数注入表单对象; 4. 执行onBind()方法; 5. 执行validator验证。 6. 执行onBindAndValidate()方法; 7. 若有err,则转到formView视图; 8. 执行onSubmit()方法或doSubmitAction()方法。 同处理get方法一样,步骤2的formBackingObject()方法一般是不会去重载的。步骤3也不需要我们做什么。真正需要我们做的是4,5,6,8步。当然4,5,6是可选的,如果有需要,可以去实现它们中的一个或几个,执行的步骤是按上面的顺序。但步骤8的两个方法是必须选一个的(两个都override是没有意义的)。 这里要说明一下onSubmit()方法和doSubmitAction()方法。在SimpleFormController中,有三种形式的onSubmit方法,它们是: * onSubmit(req, res, command, errs); * onSubmit(command, errs); * onSubmit(command); 但是这三种方法不是孤立的,第一个方法在执行中会调用第二个方法,第二个方法在执行中会调用第三个方法。一般在定义自己的SimpleFormController时只是override onSubmit(command)方法。 doSubmitAction()方法是一个有意思的方法,它的完整定义如下: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:101.13%; height:22px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td>protected void doSubmitAction(Object obj) throws Exception</td> </tr> </tbody> </table> 它的返回类型是void,而不是我们预想的ModelAndView,并且也不返回任何视图层需要的数据。实际上doSubmitAction执行完毕后会自动转到successView视图。并且如果配合sessionForm来使用的的话(sessionForm设为true),那么在转到successView视图后,在session中可以取到先前的表单对象(所谓的POJO)。 说了这么多,还是看个实例比较形象(SimpleFormController(中))。 下面是一个SimpleFormController的实例,虽然有些地方显得吹毛求疵,但主要是为了表达一个完整的流程。 首先先看配置文件,web.xml就不说了,下面的是 **/WEB-INF/mvc-config.xml**: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:97.6%; height:23px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><?xml version="1.0" encoding="UTF-8"?><br> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"<br> "<a href="http://www.springframework.org/dtd/spring-beans.dtd" rel="nofollow">http://www.springframework.org/dtd/spring-beans.dtd</a>"><br> <beans><br> <!--InternalResourceViewResolver--><br> <bean id="viewResolver"<br> class="org.springframework.web.servlet.view.InternalResourceViewResolver"><br> <property name="prefix"><br> <value>/WEB-INF/jsp/</value><br> </property><br> <property name="suffix"><br> <value>.jsp</value><br> </property><br> </bean><br> <br> <!--SimpleUrlHandlerMapping--><br> <bean id="urlHandlerMapping"<br> class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><br> <property name="mappings"><br> <props><br> <span style="color:#ff0000"><prop key="/user.htm">userController</prop></span><br> </props><br> </property><br> </bean><br> </beans></td> </tr> </tbody> </table> 然后是**/WEB-INF/controller-config.xml**: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:104.44%; height:413px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><?xml version="1.0" encoding="UTF-8"?><br> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"<br> "<a href="http://www.springframework.org/dtd/spring-beans.dtd" rel="nofollow">http://www.springframework.org/dtd/spring-beans.dtd</a>"><br> <beans><br> <br> <bean id="userValidator" class="com.yangsq.validator.UserValidator"/><br> <br> <bean id="userController"<br> class="com.yangsq.controller.UserController"><br> <property name="<span style="color:#ff0000">commandName</span>"><br> <value>command</value><br> </property><br> <property name="<span style="color:#ff0000">commandClass</span>"><br> <value>com.yangsq.domain.User</value><br> </property><br> <property name="<span style="color:#ff0000">validator</span>"><br> <ref bean="userValidator" /><br> </property><br> <property name="<span style="color:#ff0000">formView</span>"><br> <value>user</value><br> </property><br> <property name="<span style="color:#ff0000">successView</span>"><br> <value>hello</value><br> </property><br> </bean><br> </beans></td> </tr> </tbody> </table> 这里需要对上面的配置文件进行说明。commandName属性的设置是为了可以在页面中使用Spring tag,对业务流程没有影响,如果不想使用Spring tag,则这个属性可以没有。commandClass指定了封装表单的类,注意,要指定完整的路径,不能只指定一个类名,也不能<ref .../>。validator的设定说明了要使用验证器。formView和successView这两个属性设定了转向的页面,它们是父类所具有的,所以不需要在你的controller中再注入了。 下面是验证器: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:99.06%; height:22px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td> <p>import org.springframework.validation.Errors;<br> import org.springframework.validation.Validator;</p> <p>import com.yangsq.domain.User;</p> <p>public class UserValidator implements <span style="color:#ff0000">Validator</span>{ <br> <br> public boolean <span style="color:#009900">supports</span>(Class clazz) { <br> return clazz.equals(User.class);<br> }<br> <br> public void <span style="color:#009900">validate</span>(Object obj, Errors err) { <br> User user = (User) obj;<br> if (user.getPhone().length() < 7) { <br> user.setCreateTime(null);<br> err.reject("phoneErr", "电话号码位数要大于7");<br> }else if (user.getAge() <= 0) { <br> user.setCreateTime(null);<br> err.reject("ageErr", "年龄要大于0");<br> }<br> }<br> }</p> </td> </tr> </tbody> </table> 验证器实现了Validator借口,supports和validate这两个方法是必须实现的。验证器的主要任务是对表单类进行验证,这时请求的数据已经封装到表单类里了。 下面是表单类: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:102.38%; height:22px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td>public class User { <br> private String account;<br> private String phone;<br> private int age;<br> private String city;<br> private Date createTime;<br> <br> public String getAccount() { <br> return account;<br> }<br> public void setAccount(String account) { <br> this.account = account;<br> }<br> public int getAge() { <br> return age;<br> }<br> public void setAge(int age) { <br> this.age = age;<br> }<br> public String getPhone() { <br> return phone;<br> }<br> public void setPhone(String phone) { <br> this.phone = phone;<br> }<br> public Date getCreateTime() { <br> return createTime;<br> }<br> public void setCreateTime(Date createTime) { <br> this.createTime = createTime;<br> }<br> public String getCity() { <br> return city;<br> }<br> public void setCity(String city) { <br> this.city = city;<br> }<br> }</td> </tr> </tbody> </table> 属性包括用户名称,电话,年龄,城市和创建日期。此外,为了表达一个完成的演示,还创建了一个city类: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:100.72%; height:22px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td>public class City { <br> private String cityName;<br> private String cityNo;<br> public String getCityName() { <br> return cityName;<br> }<br> public void setCityName(String cityName) { <br> this.cityName = cityName;<br> }<br> public String getCityNo() { <br> return cityNo;<br> }<br> public void setCityNo(String cityNo) { <br> this.cityNo = cityNo;<br> }<br> }</td> </tr> </tbody> </table> 下面就是这个例子的主角,UserController: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:100.31%; height:22px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td> <p>public class UserController extends SimpleFormController { <br> <br> protected Map referenceData(HttpServletRequest req) throws Exception { <br> Map map = new HashMap();<br> <br> List cityList = new ArrayList();<br> City city1 = new City();<br> city1.setCityName("BeiJing");<br> city1.setCityNo("010");<br> cityList.add(city1);<br> City city2 = new City();<br> city2.setCityName("ShangHai");<br> city2.setCityNo("020");<br> cityList.add(city2);<br> <br> map.put("cityList", cityList);<br> return map;<br> }</p> <p>protected void onBind(HttpServletRequest req, Object obj) throws Exception { <br> User user = (User) obj;<br> //format the infor<br> user.setAccount(user.getAccount().trim());<br> user.setPhone(user.getPhone().trim());<br> }</p> <p><br> protected void onBindAndValidate(HttpServletRequest req, Object obj, BindException err) throws Exception { <br> User user = (User) obj;<br> user.setCreateTime(new Date());<br> }</p> <p>protected ModelAndView onSubmit(Object obj) throws Exception { <br> User user = (User) obj;<br> return new ModelAndView(this.getSuccessView(), "user", user);<br> }<br> }</p> </td> </tr> </tbody> </table> 下面是使用到的页面 user.jsp的主要部分(表单): <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:101.13%; height:22px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><FORM action="user.htm" method="post"><br> <TABLE><br> <TBODY><br> <TR><br> <TD><br> <spring:bind path="command.account"><br> 用户名:<INPUT name="${status.expression}" type="text" value="${status.value}"/><br> </spring:bind><br> </TD><br> </TR><br> <TR><br> <TD><br> <spring:bind path="command.age"><br> 年龄:<INPUT name="${status.expression}" type="text" value="${status.value}"/><br> </spring:bind><br> </TD><br> </TR><br> <TR><br> <TD><br> <spring:bind path="command.phone"><br> 电话号码:<INPUT name="${status.expression}" type="text" value="${status.value}"/><br> </spring:bind><br> </TD><br> </TR><br> <TR><br> <TD><br> <spring:bind path="command.city"><br> 城市:<br> <SELECT name="${status.expression}"><br> <c:forEach items="${cityList}" var="city" varStatus="loopStep"><br> <OPTION value="${city.cityNo}" <c:if test="${city.cityNo == status.value}">selected</c:if>><br> <c:out value="${city.cityName}"/><br> </OPTION><br> </c:forEach><br> </SELECT><br> </spring:bind><br> </TD><br> </TR><br> <TR><br> <TD><br> <spring:bind path="command.*"><br> <c:out value="${status.errorMessage}"/><br> </spring:bind><br> </TD><br> </TR><br> <TR><br> <TD align="center"><br> <INPUT type="submit" value="提交" /><br> </TD><br> </TR><br> </TBODY><br> </TABLE><br> </FORM></td> </tr> </tbody> </table> hello.jsp的主要部分: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:97.4%; height:22px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><TABLE><br> <TBODY><br> <TR><br> <TD><br> User infor:<br> </TD><br> </TR><br> <TR><br> <TD><br> <c:out value="${user.account}" /><br> </TD><br> </TR><br> <TR><br> <TD><br> <c:out value="${user.age}" /><br> </TD><br> </TR><br> <TR><br> <TD><br> <c:out value="${user.phone}" /><br> </TD><br> </TR><br> <TR><br> <TD><br> <c:out value="${user.city}" /><br> </TD><br> </TR><br> <TR><br> <TD><br> <c:out value="${user.createTime}" /><br> </TD><br> </TR><br> </TBODY><br> </TABLE></td> </tr> </tbody> </table> 在 SimpleFormController(下)会结合效果图,说明一下整个流程: 在地址栏中直接输入地址 [http://localhost:8080/SpringMVC/user.htm][http_localhost_8080_SpringMVC_user.htm](SpringMVC是工程名),会显示如下页面(user.jsp): <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:74.14%; height:306px; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=4b86f2ee0100075a&url=http://s8.sinaimg.cn/orignal/4b86f2ee7291163237d07" rel="nofollow"><img title="Spring学习笔记(十二)----SimpleFormController(下)" alt="Spring学习笔记(十二)----SimpleFormController(下)" src="http://s8.sinaimg.cn/orignal/4b86f2ee7291163237d07"></a></td> </tr> </tbody> </table> 处理原理:在地址栏输入地址提交后,实际上是对user.htm的一个get请求,在 SimpleFormController(上)里介绍了SimpleFormController对get方法的处理流程。这里会执行UserController的referenceData方法。在referenceData方法里生成了一个城市类的List。用于user.jsp(formView)的城市下来框。 在上图框体内填入信息: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:80%; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=4b86f2ee0100075a&url=http://s14.sinaimg.cn/orignal/4b86f2eea49ca8e64600d" rel="nofollow"><img title="Spring学习笔记(十二)----SimpleFormController(下)" alt="Spring学习笔记(十二)----SimpleFormController(下)" src="http://s14.sinaimg.cn/orignal/4b86f2eea49ca8e64600d"></a></td> </tr> </tbody> </table> 点击提交,会出现如下页面: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:80%; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=4b86f2ee0100075a&url=http://s3.sinaimg.cn/orignal/4b86f2ee61cd0c0cb2a82" rel="nofollow"><img title="Spring学习笔记(十二)----SimpleFormController(下)" alt="Spring学习笔记(十二)----SimpleFormController(下)" src="http://s3.sinaimg.cn/orignal/4b86f2ee61cd0c0cb2a82"></a></td> </tr> </tbody> </table> 处理原理:填入信息后点击提交,会以user.htm路径按post方法提交表单,在 SimpleFormController(上)里介绍了SimpleFormController对post方法的处理流程。在UserController里,首先会执行onBind方法,然后是UserValidator类(验证器),然后是onBindAndValidate方法。由于UserValidator类检验出了错误(电话号码位数不够),所以执行完onBindAndValidate方法后会转到user.jsp(formView)。而不会执行onSubmit方法。 修改电话号码: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:80%; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=4b86f2ee0100075a&url=http://s6.sinaimg.cn/orignal/4b86f2ee2ca79cc2dfef5" rel="nofollow"><img title="Spring学习笔记(十二)----SimpleFormController(下)" alt="Spring学习笔记(十二)----SimpleFormController(下)" src="http://s6.sinaimg.cn/orignal/4b86f2ee2ca79cc2dfef5"></a></td> </tr> </tbody> </table> 点击提交: <table style="border-bottom:#999 1px solid; border-left:#999 1px solid; width:80%; font-size:12px; border-top:#999 1px solid; border-right:#999 1px solid"> <tbody> <tr> <td><a href="http://photo.blog.sina.com.cn/showpic.html#blogid=4b86f2ee0100075a&url=http://s7.sinaimg.cn/orignal/4b86f2eebc6d29e00c9b6" rel="nofollow"><img title="Spring学习笔记(十二)----SimpleFormController(下)" alt="Spring学习笔记(十二)----SimpleFormController(下)" src="http://s7.sinaimg.cn/orignal/4b86f2eebc6d29e00c9b6"></a></td> </tr> </tbody> </table> 转到hello.jsp(successView)页面。 处理原理:填入信息后点击提交,会以user.htm路径按post方法提交表单。处理流程和上述失败时差不多。只是在执行完onBindAndValidate方法后由于没有了错误,接着执行onSubmit方法。 以上是整个的处理流程。 [Spring_----SimpleFormController]: http://s5.sinaimg.cn/orignal/4b86f2eef323726f868f4 [Spring_----SimpleFormController_Spring_----SimpleFormController]: /images/20220805/b71f985e14c94d5baa1fe6957a4a8cfe.png [http_www.javaworld.com.tw_jute_post_view_bid_42_id_152356]: http://www.javaworld.com.tw/jute/post/view?bid=42&id=152356 [http_localhost_8080_SpringMVC_user.htm]: http://localhost:8080/SpringMVC/user.htm
还没有评论,来说两句吧...