一、概述
在Struts 架構中,Controller主要是ActionServlet,但是對於業務邏輯的操作則主要由Action、ActionMapping、ActionForward這幾個組件協調完成。其中,Action扮演了真正的業務邏輯的實現者,而ActionMapping和ActionForward則指定了不同業務邏輯或流程的運行方向。
應用程序的 Controller 部分集中於從客戶端接收請求(典型情況下是一個運行浏覽器的用戶),決定執行什麼商業邏輯功能,然後將產生下一步用戶界面的責任委派給一個適當的View組件。在Struts中,controller的基本組件是一個 ActionServlet 類的servlet。這個servlet通過定義一組映射(由Java接口 ActionMapping 描述)來配置。每個映射定義一個與所請求的URI相匹配的路徑和一個 Action 類(一個實現 Action 接口的類)完整的類名,這個類負責執行預期的商業邏輯,然後將控制分派給適當的View組件來創建響應。
Struts也支持使用包含有運行框架所必需的標准屬性之外的附加屬性的 ActionMapping 類的能力。這答應我們保存特定於我們的應用程序的附加信息,同時仍可利用框架其余的特性。另外,Struts答應我們定義控制將重定向到的邏輯名,這樣一個行為方法可以請求"主菜單"頁面,而不需要知道相應的jsp頁面的實際名字是什麼。這個功能極大地幫助我們分離控制邏輯(下一步做什麼)和顯示邏輯(相應的頁面的名稱是什麼)。下圖1是Struts的controller組件示意圖:
二、創建Controller組件
Struts包括一個實現映射一個請求URI到一個行為類的主要功能的servlet。因此我們的與Controller有關的主要責任是:
為每一個可能接收的邏輯請求寫一個 Action 類(也就是,一個 Action 接口的實現);寫一個定義類名和與每個可能的映射相關的其它信息的 ActionMapping 類(也就是,一個 ActionMapping 接口的實現);寫行為映射配置文件(用XML)用來配置controller servlet。
為應用程序更新web應用程序展開描述符文件(用XML)用來包括必需的Struts組件,我們給應用程序添加適當的Struts組件。
1、Action 實現
Action 接口定義一個單一的必須由一個 Action 類實現的方法,就象下面這樣:
public ActionForward perform(ActionServlet servlet,
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException;
一個 Action 類的目標是處理這個請求,然後返回一個標識JSP頁面的 ActionForward 對象,控制應該重定向這個JSP頁面以生成相應的響應。Struts 架構為應用系統中的每一個Action類只創建一個實例。因為所有的用戶都使用這一個實例,所以你必須確定你的Action 類運行在一個多線程的環境中。下圖2顯示了一個execute()方法如何被訪問:
圖2 Action實例的execute()方法
注重,客戶自己繼續的Action子類,必須重寫execute()方法,因為Action類在默認情況下是返回null的。
在 Model 2 設計模式中,一個典型的 Action 類將在它的 perform() 方法中實現下面的邏輯:
驗證用戶session的當前狀態(例如,檢查用戶已經成功地注冊)。假如 Action 類發現沒有注冊存在,請求應該重定向到顯示用戶名和口令用於注冊的JSP頁面。應該這樣做是因為用戶可能試圖從"中間"(也就是,從一個書簽)進入我們的應用程序,或者因為session已經超時並且servlet容器創建了一個新的session。假如驗證還沒有發生(由於使用一個實現 ValidatingActionForm 接口的form bean),驗證這個 form bean 的屬性是必須的。假如發現一個問題,當作一個請求屬性保存合適的出錯信息要害字,然後將控制重定向回輸入表單這樣錯誤可以被糾正。
執行要求的處理來處理這個請求(例如在數據庫裡保存一行)。這可以用嵌入 Action 類本身的代碼來完成,但是通常應該調用一個商業邏輯bean的一個合適的方法來執行。更新將用來創建下一個用戶界面頁面的服務器端對象(典型情況下是request范圍或session范圍beans,定義我們需要在多長時間內保持這些項目可獲得)。返回一個標識生成響應的JSP頁面的適當的 ActionForward 對象,基於新近更新的beans。典型情況下,我們將通過接收到的 ActionMapping 對象(假如我們使用一個局部於與這個映射上的邏輯名)或者在controller servlet 本身(假如我們使用一個全局於應用程序的邏輯名)上調用 findForward() 得到一個對這樣一個對象的引用。
當為 Action 類編程時要記住的設計要點包括以下這些:
controller servlet僅僅創建一個我們的 Action 類的實例,用於所有的請求。這樣我們需要編寫我們的 Action 類使其能夠在一個多線程環境中正確運行,就象我們必須安全地編寫一個servlet的 service() 方法一樣。
幫助線程安全編程的最重要的原則就是在我們的 Action 類中僅僅使用局部變量而不是實例變量。局部變量創建於一個分配給每個請求線程的棧中,所以沒有必要擔心會共享它們。
盡管不應該,代表我們的系統中Model部分的的beans仍有可能拋出違例。我們應該在我們的 perform() 方法的邏輯中捕捉所有這樣的違例,並且通過執行以下語句將它們記錄在應用程序的日志文件中(包括相應的棧跟蹤信息):