第一個 Struts 程式


使用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>