org.springframework.web.servlet.mvc.AbstractWizardFormController 可以讓您設計出如桌面應用程式的精靈(Wizard),通常用於問卷表單內容相當長時,與其使用一個表單呈現所有的問卷內容,不如將問卷內容分作數個畫 面,讓使用者一頁一頁完成問卷,您可以繼承AbstractWizardFormController,並重新定義它的processFinish()方 法,當中定義的是全部問卷提交完後的處理,例如:
- WizardController.java
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的類別設計如下:
- Questionaire.java
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"屬性來決定,例如:
- 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>
<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的撰寫:
- 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按鈕後,會顯示第二個頁面:
- question1.jsp
<%@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是最後一個問卷,來看看它是如何撰寫的:
- 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來顯示結果:
- 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>
....
<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");
}
...
protected ModelAndView processFinish(
HttpServletRequest request,
HttpServletResponse response,
Object command,
BindException exception) throws Exception {
return new ModelAndView("start");
}
...