org.springframework.web.servlet.mvc.AbstractWizardFormController 可以让您设计出如桌 面应用程式的精灵(Wizard),通常用于问卷表单内容相当长时,与其使用一个表单呈现所有的 问卷内容,不如将问卷内容分作数个画 面,让使用者一页一页完成问卷,您可以继承 AbstractWizardFormController,并重新定义它的 processFinish()方 法,当中定义的是全部 问卷提交完后的处理,例如:
package onlyfun.caterpillar; import java.util.*; import javax.servlet.http.*; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractWizardFormController; import org.springframework.validation.BindException; public class WizardController extends AbstractWizardFormController { private String successView; public WizardController() { setCommandClass(Questionnaire.class); } protected ModelAndView processFinish( HttpServletRequest request, HttpServletResponse response, Object command, BindException exception) throws Exception { Questionnaire questionnaire = (Questionnaire) command; Map model = new HashMap(); model.put("q1", questionnaire.getQuestion1()); model.put("q2", questionnaire.getQuestion2()); model.put("q3", questionnaire.getQuestion3()); return new ModelAndView(getSuccessView(), "ans", model); } public void setSuccessView(String successView) { this.successView = successView; } public String getSuccessView() { return successView; } }
所有的问卷结果收集在一个 Command 物件中,上面的程式只是将结果取得并设定在 Model 资料物 件中,以在 View 上呈现资料,Command 的类别设计如下:
package onlyfun.caterpillar; public class Questionnaire { private String question1; private String question2; private String question3; public void setQuestion1(String question1) { this.question1 = question1; } public void setQuestion2(String question2) { this.question2 = question2; } public void setQuestion3(String question3) { this.question3 = question3; } public String getQuestion1() { return question1; } public String getQuestion2() { return question2; } public String getQuestion3() { return question3; } }
问卷的流程是规范在 Bean 定义档中,藉由设定 AbstractWizardFormController 的"pages"属性 来决定,例如:
<?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="urlMapping" class="org.springframework.web.servlet. → handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/wizard.do">wizardController</prop> </props> </property> </bean> <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> <bean id="wizardController" class="onlyfun.caterpillar.WizardController"> <property name="successView"> <value>success</value> </property> <property name="pages"> <list> <value>start</value> <value>question1</value> <value>question2</value> <value>question3</value> </list> </property> </bean> </beans>
依以上的设定,问卷将依 start.jsp、question1.jsp、question2.jsp、 question3.jsp 的顺序来完成,首先看看 start.jsp 的撰写:
<%@page contentType="text/html"%> <%@page?pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Start Page</title> </head> <body> <form name="questionform" action="/AbstractWizardDemo/wizard.do" method="POST"> 欢迎您填写问卷! <input type="submit" value="Start" name="_target1"/> </form> </body> </html>
当您连接至 Wizard 控制器时,预设会取得设定档中索引 0 位置的网页来显示,第一个页面通常 是欢迎或问卷说明页面,决定下一个要展示的页面之方法,在于 请求中有无带有一个"_target" 开头,并跟着一个号码的请求参数,例如"_target1"这样的设定,号码表示在设定档中< list> 的顺序,上面的网页在按下 Start 按钮后,会显示第二个页面:
<%@page contentType="text/html"%> <%@page?pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Question 1</title> </head> <body> <form name="questionform1" action="/AbstractWizardDemo/wizard.do" method="POST"> 问题一 <input type="text" name="question1"/><br> <input type="submit" value="Previous" name="_target0"/> <input type="submit" value="Next" name="_target2"/> </form> </body> </html>
依"_target"与号码来决定显示的页面是 getTaretPage()方法所预设的,必要的话,您也可以重 新定义这个方法以决定下一个页面由哪一个 参数决定,在 question1.jsp 的设计中,按下 Previous 按钮的话,会返回问卷的上一页,按下 Next 的按钮的话,会返回问卷的下一页, question2.jsp 的设计也是类似。
决定是否完成问卷的方式,在于检验请求中是否有请求参数"_finish",如果检查到有这个值, 就会执行 processFinish()方法,question3.jsp 是最后一个问卷,来看看它是如何撰写的:
<%@page?contentType="text/html"%> <%@page?pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Question 3</title> </head> <body> <form name="questionform3" action="/AbstractWizardDemo/wizard.do" method="POST"> 问题三 <input type="text" name="question3"/><br> <input type="submit" value="Previous" name="_target2"/> <input type="submit" value="Finish" name="_finish"/> </form> </body> </html>
记得最后一个送出的问卷要带有一个"_finish"参数,才会执行 AbstractWizardFormControlle 的 processFinish()方法,最后设计一个 success.jsp 来显示结果:
<%@page contentType="text/html"%> <%@page?pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Success</title> </head> <body> <H1>Q1: ${ans.q1}</H1> <br> <H1>Q2: ${ans.q2}</H1> <br> <H1>Q3: ${ans.q3}</H1> <br> </body> </html>
您也可以在问卷中设计一个 Cancel 按钮,在按下该按钮后,可以送出"_cancel"请求参数,例如:
.... <form name="questionform3" action="/AbstractWizard/wizard.do" method="POST"> .... <input type="submit" value="Cancel" name="_cancel"/> </form> ....
当请求中带有"_cancel"请求参数时,则会呼叫 processCancel()方法,您可以重新定义这个方 法,例如将使用者送回问卷开始时:
... protected ModelAndView processFinish( HttpServletRequest request, HttpServletResponse response, Object command, BindException exception) throws Exception { return new ModelAndView("start"); } ...