使用Struts來撰寫一個基於 MVC 架構的Web程式是簡單的,以下用一個簡單的實例來示範如何使用Struts,您也可以從中瞭解到具體的MVC工作流程。
首先請至 Struts 官方網站 下載Struts,這邊下載的是jakarta-struts-1.2.4.zip,解開後您可以在lib目錄下找到struts.jar以及一些相依的 jar檔 ,對於第一個Struts程式來說,您需要以下的jar檔,請將這些檔案複製至您的Web應用程式的/WEB-INF/lib目錄下:
- struts.jar
- commons-beanutils.jar
- commons-digester.jar
- commons-collections.jar
- commons-logging.jar
值得一提的是,在Struts的下載檔案中,/webapps目錄是一些Struts的範例,將來您可以參考這些範例中的一些設定與設計方式來開發程式, 其中struts-blank.war是一個開發Struts的基礎,具備了Struts的基礎設定檔案及設定,您可以用它來開速開發Web應用程式。
在Struts中,擔任Front Controller角色的是ActionServlet,理想上所有客戶端請求都透過它來完成轉發,必須在/WEB- INF/web.xml中設定:
- web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 
    version="2.4">
 <!-- 注意,xsi那行是沒換行的,排版關係才作了換行 -->
 <!-- 如果您是直接拷貝這個設定,請自行接上該行 -->
    <description> 
        Struts Web Application
    </description>
    <display-name>Struts Web Application</display-name>
    <!-- Standard Action Servlet Configuration --> 
    <servlet> 
        <servlet-name>action</servlet-name> 
        <servlet-class>
            org.apache.struts.action.ActionServlet
        </servlet-class> 
        <init-param> 
            <param-name>config</param-name> 
            <param-value>
                /WEB-INF/conf/struts-config.xml
            </param-value> 
        </init-param> 
        <load-on-startup>2</load-on-startup> 
    </servlet> 
    <!-- Standard Action Servlet Mapping --> 
    <servlet-mapping> 
        <servlet-name>action</servlet-name> 
        <url-pattern>*.do</url-pattern> 
    </servlet-mapping>
</web-app>org.apache.struts.action.ActionServlet的設定中,設定config參數的作用是設定struts-config.xml的檔案來源,struts-config.xml中包括了所有Struts的相關請求轉發,以及一些資源設定。
在ActionServlet的servlet-mapping設定中,將所有以*.do結尾的請求交給ActionServlet來處理。
接下來看看struts-config.xml的設定:
- struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
 "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
 "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
 <struts-config> 
    <action-mappings> 
        <action 
            path="/hello" 
            type="onlyfun.caterpillar.HelloAction"> 
            <forward
                name="helloUser" 
                path="/WEB-INF/pages/hello.jsp"/> 
        </action> 
    </action-mappings> 
</struts-config>在struts-config.xml中,定義了<action-mappings>,這當中關係到請求與資源的轉發設定對應,< action>中設定了path為/hello,這表示請求的資源若是/hello.do,則會呼叫HelloAction 來處理這個請求(type屬性設定的),<forward>設定則是HelloAction處理完畢之後的轉發對象,一個< action>中可以有多個 <forward>,在Action物件中將根據<forward>上的name來查找並返回對應的ActionForward 物件,ActionServlet會根據 Action 傳回的ActionForward來將請求轉發至指定的對象。
來看看HelloAction,在Struts中,一個Action物件必須繼承org.apache.struts.action.Action,並覆寫其execute()方法,看看HelloAction是如何撰寫的:
- HelloAction.java
package onlyfun.caterpillar;
import java.util.*;
import javax.servlet.http.*;
import org.apache.struts.action.*; 
public class HelloAction extends Action {
    public ActionForward execute(
                             ActionMapping mapping, 
                             ActionForm form, 
                             HttpServletRequest request, 
                             HttpServletResponse response) 
                                  throws Exception {
        // get information from request object
        String username = request.getParameter("user");
        // prepare model
        Map model = new HashMap();
        if(username != null)
            model.put("username", username);
        else
            model.put("username", "nobody");
        // pass information to View by using reqeust object
        request.setAttribute("userInfo", model);
        return mapping.findForward("helloUser");
    }
}這邊先關心一些execute()中傳入的request與response,而暫不理會另兩個參數,request與 response是HttpServletRequest及HttpServletResponse的實例,就如何在一個簡單的Servlet一樣,您可 以使用這兩個物件來分別取得請求與回應的相關資源。
Action物件是Controller角色,如您在程式中所看到的,在Action物件中,您所要作的是:
- 取得請求中的相關參數
- 驗證資料的邏輯正確性
- 將請求參數複製給商務物件
- 取得執行結果並準備結果
- 轉發給View物件
第一個Struts程式很簡單,所以暫且沒有使用到商務物件,在真正的程式中,您會使用到商務物件(Model)來處理商務,而您的Action中之邏輯應該只包括請求資訊的收集、轉交商務請求給業務物件、準備View所需要的資料等有關。
在View所需要的物件準備上,程式中使用了Map物件,在實際的程式中,您可以設計自己的資料Model物件。您可以看到,Struts會使用標準 JSP/Servlet相關物件的setAttribute()與getAttribute()方法來向View傳遞Model,在程式中使用的是 request物件的setAttribute()。
在Web MVC中,使用者的請求相關資訊就到Action中就要結束了,所有的相關訊息必須複製為資料傳輸物件再設定給商務物件,而不是直接將請求相關物件或訊息 直接傳遞至商務層,這樣作可以使得Web層不會與接下來的商務層緊密耦合。另一方面,View層的資料要透過資料Model物件來取得,而不是直接從使用 者的請求物件中獲得。
在execute()方法中傳入的ActionMapping物件,代表了struts-config.xml中<action- mappings>的設定物件,findForward()方法會尋找指定的forward資源name名稱,如果找到,就傳回一個 ActionForward物件,當中包括了轉發的目的物件,目的地即path屬性設定的路徑。
回顧一下struts-config.xml,注意到"helloUser"的forward目的地是/WEB- INF/pages/hello.jsp,將資源放在/WEB-INF目錄下,使用者就只能透過Controller的轉發來取得資源,這是一個較具安全 性的作法。
hello.jsp如下:
- hello.jsp
<html> 
<head> 
<title>Hello, \${userInfo["username"]} !</title> 
</head> 
<body>
    <H1>Hello, \${userInfo["username"]} !</H1> 
</body> 
</html>在這邊先使用JSP 2.0所提供的Express Language新功能來取得設定於request中的Model物件之資料,Struts提供有一組可以與其配合的標籤庫(Tag Library),如果您的View層技術使用的是JSP資源,也可以善加利用。
來檢驗一下第一個Struts的成果,啟動您的Web Container,並在瀏覽器輸入:
http://localhost:8080/strutsapp/hello.do?user=Justin
      
      您將會得到以下的內容:
<html> 
<head>
<title>Hello, Justin !</title>
</head>
<body>
      
<H1>Hello, Justin !</H1>
      
</body>
</html>
      
<head>
<title>Hello, Justin !</title>
</head>
<body>
<H1>Hello, Justin !</H1>
</body>
</html>

