AbstractWizardFormController


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>
....

當請求中帶有"_cancel"請求參數時,則會呼叫processCancel()方法,您可以重新定義這個方法,例如將使用者送回問卷開始時:
...
    protected ModelAndView processFinish(
                   HttpServletRequest request,
                   HttpServletResponse response,
                   Object command,
                   BindException exception) throws Exception {
        return new ModelAndView("start");
    }
...