在使用Eclipse或者Netbeans之类的IDE进行开发的时候,如果我们要新建一个工程后者文件,这些IDE通常都会提供多步的向导
帮助我们一步步完成相应的部件创建,在某些Web应用程序中,也存在类似的操作场景,比如要注册某个网站的会员,注册过程
可能就包括多步,每一步会提示输入某一方面的信息,以帮助我们简化操作流程。对于这种向导式的简单的多页面流程实现,
我们可以求助于AbstractWizardFormController,它可以帮助我们简化类似场景的开发工作。
其实,AbstractWizardFormController实现类就是要处理组成向导流程的所有页面所发起的Web请求,但与SimpleFormController
处理单个页面不同,AbstractWizardFormController要管理多个表单的显示以及提交数据的处理工作
AbstractWizardFormController将根据每个页面请求后包含的特定参数来决定如何对当前请求进行处理,这些特定参数可以分为如下三类:
PARAM_TARGET PARAM_TARGET用于指定目标页面,它的形式为_target后缀页面索引,比如_target0,_target1,当AbstractWizardFormController
接受到这种类型的参数的时候,它只是将当前请求中的相应参数绑定到Command对象上,然后根据PARAM_TARGET参数后缀的目标页面索引显示相应页面
PARAM_FINISH参数:PARAM_FINISH参数的表现形式为_finish ,当AbstractWizardFormController接受到这种类型的参数的时候
则表示整个向导流程结束,可以调用processFinish()方法处理最终的表单数据,并将页面转向任何一个想要转到的页面
PARAM_CANCEL参数:PARAM_CANCEL参数的形式为_cancel,当接受到该参数的时候,表示用户要取消当前的向导流程,默认情况下
AbstractWizardFormController不支持该参数的处理,但我们可以通过覆写processCancel()方法来改变这种默认的行为,唯一要做的
可能只是返回一个ModelAndView实例,其中只包含了一个逻辑视图名
实际上,AbstractWizardFormController实现类本质上依然是像SimpleFormController那样,分两个阶段来管理表单页面的处理,
只不过从逻辑上将单个表单页面划分为了多个表单页面,而最终绑定数据的Command对象只有一个,AbstractWizardFormController
将根据_targetX参数决定显示表单页面的某一部分,对应到视图那就是显示哪个导向页面。在提交请求之后,AbstractWizardFormController
会把它显示并提交的那部分数据绑定到唯一的那个Command那个对象上,只有在所有导向页面都提交之后,Command对象的数据
才算绑定完成。
在向导最终结束的画面提交_finish参数之后,AbstractWizardFormController将从Command对象获取到所有导向页面收集来的数据
,然后可以调用processFinish方法开始”压轴戏“,实际上,在实现AbstractWizardFormController的时候,也只有processFinish
方法是我们必须要去实现的。
下面是我从别人博客上看到,我实现的例子
首先是 springMVC.xml
01 | bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> |
02 | < property name = "mappings" > |
04 | < prop key = "login.do" >registerController</ prop > |
10 | < bean id = "registerController" class = "com.web.springMVC.controller.RegisterController" > |
11 | < property name = "successView" > |
12 | < value >success</ value > |
14 | < property name = "cancelView" > |
17 | < property name = "commandClass" > |
18 | < value >com.web.springMVC.model.RegisterInfo</ value > |
20 | < property name = "pages" > |
23 | < value >register1</ value > |
24 | < value >register2</ value > |
25 | < value >register3</ value > |
31 | class = "org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" ></ bean > |
34 | class = "org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" ></ bean > |
37 | < bean id = "viewResolver" |
38 | class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > |
39 | < property name = "prefix" value = "/WEB-INF/jsp/" ></ property > |
40 | < property name = "suffix" value = ".jsp" ></ property > |
对于pages属性,定义了所有的表单页,注意顺序,在填写时,将按照这个顺序进行。
继承自AbstractWizardFormController的controller类如下:
01 | public class RegisterController extends AbstractWizardFormController{ |
04 | * successView是特地添加的一个属性,用于提供问卷结束后应该导向的视图名称,不要将它与SimpleFormC ontroller |
05 | * 的successView混淆,SimpleFormController已经为我们定义了这么一个属性,而AbstractWizardFormController没有 |
08 | private String successView; |
09 | private String cancelView; |
10 | public String getSuccessView() { |
13 | public void setSuccessView(String successView) { |
14 | this .successView = successView; |
16 | public String getCancelView() { |
19 | public void setCancelView(String cancelView) { |
20 | this .cancelView = cancelView; |
23 | * 实现一个AbstractWizardFormController必须要提供的覆写方法是processFinish() |
24 | * 在该方法中调用服务对象将当前的调查结果告知系统,然后将返回的总的问卷的调查情况,通过ModelAndView |
25 | * 公开给下一个页面,也就是successView对应的最终的结果显示页面 |
27 | protected ModelAndView processFinish(HttpServletRequest req,HttpServletResponse res,Object command,BindException errs ) throws Exception{ |
28 | RegisterInfo registerInfo=(RegisterInfo)command; |
29 | return new ModelAndView( this .getSuccessView(), "registerInfo" ,registerInfo); |
32 | protected ModelAndView processCancel(HttpServletRequest req,HttpServletResponse res,Object command,BindException errs) throws Exception{ |
33 | return new ModelAndView( this .getCancelView()); |
36 | * RegisterController继承了AbstractWizardFormController,所以必须实现他的abstract method---processFinish。也就是说,如果继承了AbstractWizardFormController |
37 | * 仅需要实现这个方法,当所有的页面表单填写完将调用这个方法,processCancel方法不是必须实现的,他是在你填写某一步表单时想取消,按取消按钮时调用。 |
RegisterController继承了AbstractWizardFormController,所以必须实现他的abstract mothed---processFinish。也就是说,若果继承了AbstractWizardFormController,你仅需要实现这个方法。
当所有的页面表单填写完将调用这个方法。 processCancel方法不是必须实现的,他是在你填写某一步表单时想取消,按取消按钮时调用。
下面是表单类RegisterInfo
01 | public class RegisterInfo { |
05 | private String adress; |
注意,它可不是某一页的表单类,而是所有页的表单信息的总和。
下面就是页面了/WEB-INF/jsp/main.jsp:
02 | < form action = "login.do" method = "post" > |
05 | < td >注册信息,请认真填写! < input type = "submit" value = "开始" name = "_target1" /> |
下面就是页面了/WEB-INF/jsp/register1.jsp:
02 | < form action = "login.do" method = "post" > |
06 | < td >姓名:< input name = "name" type = "text" /> |
10 | < td >年龄:< input name = "age" type = "text" /> |
14 | < td >性别: < select name = "sex" > |
15 | < option value = "Y" >男</ option > |
16 | < option value = "X" >女</ option > |
22 | < input type = "submit" value = "上一步" name = "_target0" /> |
23 | < input type = "submit" value = "下一步" name = "_target2" /> |
24 | < input type = "submit" value = "取消" name = "_cancel" /> |
下面就是页面了/WEB-INF/jsp/register2.jsp:
02 | < form action = "login.do" method = "post" > |
06 | < td >地址:< input name = "adress" type = "text" /> |
10 | < td >电话:< input name = "phone" type = "text" /> |
14 | < td >电子邮件:< input name = "emial" type = "text" /> |
19 | < input type = "submit" value = "上一步" name = "_target1" /> |
20 | < input type = "submit" value = "下一步" name = "_target3" /> |
21 | < input type = "submit" value = "取消" name = "_cancel" /> |
下面就是页面了/WEB-INF/jsp/register3.jsp:
02 | < form action = "login.do" method = "post" > |
04 | < td >喜好:< br > < textarea rows = "8" cols = "40" name = "favor" |
05 | style = "background-color: D7F8AB" ></ textarea > |
09 | < td align = "center" >< input type = "submit" value = "上一步" |
10 | name = "_target2" /> < input type = "submit" value = "完成" name = "_finish" /> |
11 | < input type = "submit" value = "取消" name = "_cancel" /></ td > |
下面就是页面了/WEB-INF/jsp/success.jsp:
08 | < td >< c:out value = "${registerInfo.name}" ></ c:out ></ td > |
11 | < td >< c:out value = "${registerInfo.age}" ></ c:out ></ td > |
14 | < td >< c:out value = "${registerInfo.sex}" ></ c:out ></ td > |
17 | < td >< c:out value = "${registerInfo.adress}" ></ c:out ></ td > |
20 | < td >< c:out value = "${registerInfo.phone}" ></ c:out ></ td > |
23 | < td >< c:out value = "${registerInfo.email}" ></ c:out ></ td > |
26 | < td >< c:out value = "${registerInfo.favor}" ></ c:out ></ td > |
注意用input的name属性,其中_target加数字指示的是RegisterController的bean配置文件里pages属性里定义的页面。
注意_target的数字是从0开始的,也就是说_target0代表main.jsp,_target1代表register1.jsp,_target2代表register2.jsp,
_target3代表register3.jsp。当点击相应的按钮时会转到name指示的页面。还有两个name属性值需要说明,_finish表示完成,
点击其按钮会调用controller的processFinish方法,_cancel表示取消,点击其按钮会调用controller的processCancel方法。