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