一個請求在Struts2框架中的處理大概分為以下幾個步驟:
1 客戶端初始化一個指向Servlet容器(例如Tomcat)的請求;
2 這個請求經過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對於Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)
3 接著FilterDispatcher被調用,FilterDispatcher詢問ActionMapper來決定這個請是否需要調用某個Action
4 如果ActionMapper決定需要調用某個Action,FilterDispatcher把請求的處理交給ActionProxy
5 ActionProxy通過Configuration Manager詢問框架的配置文件,找到需要調用的Action類
6 ActionProxy創建一個ActionInvocation的實例。
7 ActionInvocation實例使用命名模式來調用,在調用Action的過程前後,涉及到相關攔截器(Intercepter)的調用。
8 一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果通常是(但不總是,也可 能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts2 框架中繼承的標簽。在這個過程中需要涉及到ActionMapper
在上述過程中所有的對象(Action,Results,Interceptors,等)都是通過ObjectFactory來創建的。
Struts2的目標很簡單--使Web開發變得更加容易。為了達成這一目標,Struts2中提供了很多新特性,比如智能的默認設置、annotation的使用以及"慣例重於配置"原則的應用,而這一切都大大減少了XML配置。Struts2中的Action都是POJO,這一方面增強了Action本身的可測試性,另一方面也減小了框架內部的耦合度,而HTML表單中的輸入項都被轉換成了恰當的類型以供action使用。開發人員還可以通過攔截器(可以自定義攔截器或者使用Struts2提供的攔截器)來對請求進行預處理和後處理,這樣一來,處理請求就變得更加模塊化,從而進一步減小耦合度。模塊化是一個通用的主題--可以通過插件機制來對框架進行擴展;開發人員可以使用自定義的實現來替換掉框架的關鍵類,從而獲得框架本身所不具備的功能;可以用標簽來渲染多種主題(包括自定義的主題);Action執行完畢以後,可以有多種結果類型--包括渲染JSP頁面,Velocity和Freemarker模板,但並不僅限於這些。最後,依賴注入也成了Struts2王國中的一等公民,這項功能是通過Spring框架的插件和Plexus共同提供的,與PicoContainer的結合工作還正在進行中
Struts 2設計的精巧之處就是使用了Action代理,Action代理可以根據系統的配置,加載一系列的攔截器,由攔截器將HttpServletRequest參數解析出來,傳入Action。同樣,Action處理的結果也是通過攔截器傳入HttpServletResponse,然後由HttpServletRequest傳給用戶。
其實,該處理過程是典型的AOP(面向切面編程)的方式,讀者可以在後面詳細了解到。Struts 2處理過程模型如圖3.2所示。
圖3.2 Struts 2處理過程模型
★ 說明 ★
攔截器是Struts 2框架的核心,通過攔截器,實現了AOP(面向切面編程)。使用攔截器,可以簡化Web開發中的某些應用,例如,權限攔截器可以簡化Web應用中的權限檢查。
業務控制器Action是由開發者自己編寫實現的,Action類可以是一個簡單的Java類,與Servlet API完全分離。Action一般都有一個execute()方法,也可以定義其他業務控制方法,詳細內容將在後面介紹。
Action的execute()返回一個String類型值,這與Struts 1返回的ActionForward相比,簡單易懂。Struts 2提供了一個ActionSupport工具類,該類實現了Action接口和validate()方法,一般開發者編寫Action可以直接繼承ActionSupport類。編寫Action類後,開發者還必須在配置文件中配置Action。一個Action的配置應該包含下面幾個元素:
— 該Action的name,即用戶請求所指向的URL。
— Action所對應的class元素,對應Action類的位置。
— 指定result邏輯名稱和實際資源的定位。
Action是業務控制器,筆者建議在編寫Action的時候,盡量避免將業務邏輯放到其中,盡量減少Action與業務邏輯模塊或者組件的耦合程度。
業務模型組件可以是實現業務邏輯的模塊,可以是EJB、POJO或者JavaBean,在實際開發中,對業務模型組件的區分和定義也是比較模糊的,實際上也超出了Struts 2框架的范圍。不同的開發者或者團隊,都有自己的方式來實現業務邏輯模塊,Struts 2框架的目的就是使用Action來調用業務邏輯模塊。例如一個銀行存款的業務邏輯模塊,如代碼3.3所示。
代碼3.3 模擬一個銀行業務的實現模塊
package ch3;
public class Bank {
//定義銀行賬戶
private String accounts;
//定義操作金額
private double money;
//屬性的getter和setter方法
public String getAccounts() {
return accounts;
}
public void setAccounts(String accounts) {
this.accounts = accounts;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
//模擬銀行存款方法
public boolean saving(String accounts, double money) {
//調用DAO等模塊讀寫數據庫
return dosomeing();
}
}
上面實例在實際開發中沒有任何意義,這裡只是作為業務邏輯模塊來說明,在執行saving(String accounts,double money)方法時,可以調用相應的數據庫訪問其他組件,來實現存款操作。使用Action調用該業務邏輯組件可以在execute()方法中實現,如代碼3.4所示。
代碼3.4 業務控制器Bank_Saving_Action
package ch3;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class Bank_Saving_Action extends ActionSupport {
//定義銀行賬戶
private String accounts;
//定義操作金額
private double money;
public String execute() throws Exception {
//創建Bank實例
Bank bk=new Bank();
//調用存款方法
if (bk.saving(accounts, money)){
return SUCCESS;
}else{
return ERROR;
}
}
//屬性的getter和setter方法
public String getAccounts() {
return accounts;
}
public void setAccounts(String accounts) {
this.accounts = accounts;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
Bank_Saving_Action演示了對銀行存款業務邏輯組件的調用,這裡是通過在Action中創建業務邏輯組件實例的方式實現的。在實際開發中,可以使用靜態工廠獲得業務邏輯組件的實例或者使用IoC容器來管理。Action中不實現任何業務邏輯,只是負責組織調度業務邏輯組件。調用關系如圖3.3所示。
圖3.3 調用業務邏輯組件
★ 說明 ★
業務控制器Action一般情況下不是直接創建業務邏輯組件實例,而是使用工廠模式或者是從Spring容器中獲得業務邏輯組件實例,這樣可以提高系統的性能。
Struts 1只能支持JSP作為視圖資源,而Struts 2的進步之處就是可以使用其他視圖技術,如FreeMarker、Velocity等。通過前面的學習和示例,讀者會知道Action的返回結果只是一個簡單的字符串,也就是一個邏輯上的視圖名稱,要與實際視圖資源對應,必須通過配置文件來實現。
在struts.xml配置文件中,每一個Aciton定義都有name和class屬性,同時還要指定result元素。result元素指定了邏輯視圖名稱和實際視圖的對應關系。每個result都有一個type屬性,前面介紹的struts.xml中並沒有顯式指定type值,即使用了默認的type類型:dispatcher,該結果類型支持JSP所謂視圖資源。