第四章 Struts框架之構建Controller組件(2 / 3)

包括在Struts中的例子程序某種程度上延伸了這個設計原則,因為商業邏輯本身是嵌入到Action類中的。這應該被看作是在這個樣本應用程序設計中的一個bug,而不是一個Struts體係結構中的固有特性,或者是一個值得仿效的方法。

2、ActionMapping實現

為了成功地運行,Struts的controllerservlet需要知道關於每個URI該怎樣映射到一個適當的Action類的幾件事。需要了解的知識封裝在一個叫做ActionMapping的Java接口中,它有以下屬性:

actionClass:用於這個映射的Action類完整的Java類名。第一次一個特定的映射被使用,一個這個類的實例將被創建並為以後重用而保存。

formAttribute:session範圍的bean的名字,當前的這個映射的ActionForm被保存在這個bean之下。如果這個屬性沒有被定義,沒有ActionForm被使用。

formClass:用於這個映射的ActionForm類完整的Java類名。如果我們在使用對formbeans的支持,這個類的一個實例將被創建並保存(在當前的用戶會話中)

path:匹配選擇這個映射的請求的URI路徑。看下麵如何匹配的例子。

Struts在一個叫做ActionMappingBase的類中包括了一個ActionMapping接口的方便的實現。如果我們不需要為我們自己的映射定義任何附加的屬性,盡管把這個類作為我們的ActionMapping類好了,就向下麵部分描述的那樣配置。然而,定義一個ActionMapping實現(多半是擴展ActionMappingBase類)來包含附加的屬性也是可能的。controllerservlet知道怎樣自動配置這些定製屬性,因為它使用Struts的Digester模塊來讀配置文件。

包括在Struts的例子程序中,這個特性用來定義兩個附加的屬性:

failure:如果Action類檢測到它接收的輸入字段的一些問題,控製應該被重定向到的上下文相關的URI。典型情況下是請求發向的JSP頁麵名,它將引起表單被重新顯示(包含Action類設置的出錯消息和大部分最近的來自ActionFormbean的輸入值)。

success:如果Action類成功執行請求的功能,控製應該被重定向到的上下文相關的URI。典型情況下是準備這個應用程序的會話流的下一個頁麵的JSP頁麵名。

使用這兩個額外的屬性,例子程序中的Action類幾乎完全獨立於頁麵設計者使用的實際的JSP頁麵名。這個頁麵可以在重新設計時被重命名,然而幾乎不會影響到Action類本身。如果"下一個"JSP頁麵的名字被硬編碼到Action類中,所有的這些類也需要被修改。

3、ActionForward實現

目的是控製器將Action類的處理結果轉發至目的地。

Action類獲得ActionForward實例的句柄,然後可用三種方法返回到ActionServlet,所以我們可以這樣使用ActionForward():ActionServlet根據名稱獲取一個全局轉發;ActionMappin實例被傳送到perform()方法,並根據名稱找到一個本地轉發。

另一種是調用下麵的一個構造器來創建它們自己的一個實例:

publicActionForward()

publicActionForward(Stringpath)

publicActionForward(Stringpath,Booleanredirect)

4、Action映射配置文件

controllerservlet怎樣知道我們想要得到的映射?寫一個簡單地初始化新的ActionMapping實例並且調用所有適當的set方法的小的Java類是可能的(但是很麻煩)。為了使這個處理簡單些,Struts包括一個Digester模塊能夠處理一個想得到的映射的基於XML的描述,同時創建適當的對象。

開發者的責任是創建一個叫做action.xml的XML文件,並且把它放在我們的應用程序的WEB-INF目錄中。(注意這個文件並不需要DTD,因為實際使用的屬性對於不同的用戶可以是不同的)最外麵的XML元素必須是<action-mappings>,在這個元素之中是嵌入的0個或更多的<action>元素--每一個對應於我們希望定義的一個映射。

來自例子程序的action.xml文件包括"注冊"功能的以下映射條目,我們用來說明這個需求:

<action-mappings>

<forwardname="logon"path="/logon.jsp"/>

<actionpath="/logon"actionClass="org.apache.struts.example.LogonAction"

formAttribute="logonForm"formClass="org.apache.struts.example.LogonForm"inputForm="/logon.jsp">

<forwardname="success"path="/mainMenu.jsp"/>

</action>

</action-mappings>

就象我們所看到的,這個映射匹配路徑/logon(實際上,因為例子程序使用擴展匹配,我們在一個JSP頁麵指定的請求的URI結束於/logon.do)。當接收到一個匹配這個路徑的請求時,一個LogonAction類的實例將被創建(僅僅在第一次)並被使用。controllerservlet將在關鍵字logonForm下查找一個session範圍的bean,如果需要就為指定的類創建並保存一個bean。

這個action元素也定義了一個邏輯名"success",它在LogonAction類中被用來標識當一個用戶成功注冊時使用的頁麵。象這樣使用一個邏輯名允許將action類隔離於任何由於重新設計位置而可能發生的頁麵名改變。

這是第二個在任何action之外宣告的forward元素,這樣它就可以被所有的action全局地獲得。在這個情況下,它為注冊頁麵定義了一個邏輯名。當我們調用mapping.findForward()時在我們的action代碼中,Struts首先查找這個action本地定義的邏輯名。如果沒有找到,Struts會自動為我們查找全局定義的邏輯名。