從字面上看,Struts 2好像是Struts 1的升級版本,其實Struts 2更像是WebWork,Apache之所以命名爲Struts 2,筆者認爲有如下原因:
Struts 1.X是目前應用最早的一種MVC架構,經過了多年的考驗,被廣大Java開發者所接受,大量的Java Web應用中使用了Struts 1.X,證明了Struts 1出色的穩定性和可用性。Struts 1成爲Apache成功的產品之一。
WebWork興起時間比較短,儘管展示了其更加先進的技術優勢,但是被開發者接受需要時間的驗證,至少國內目前使用WebWork架構開發案例比較少,更多使用WebWork架構搭建的系統一般都是出於學習和測試的目的。
Apache接手WebWork項目後,有意於藉助Struts 1.X在業界的成功來推廣Struts 2。Struts 2非常類似於WebWork框架,而不是Struts 1.X框架,是以WebWork爲核心來實現的。
從Struts 1.X過渡到Struts 2所改變的東西比較多,但是隻要領會了MVC設計思想和Java Web開發的理念,讀者會發現,Struts 2將比Struts 1.X更加簡單,更加靈活。如果讀者熟悉WebWork框架,那麼學習Struts 2是一件比較容易的事情。
1.4.1 Struts 2框架
Struts 2相對於Struts 1.X,將實現用戶業務邏輯(Action)同Servlet API分離開,這種分離機制,是採用了攔截器或者攔截器棧(攔截器鏈)。攔截器是Struts 2的核心內容之一。
Struts 2內建了多個攔截器和攔截器棧(由多個攔截器形成的攔截器鏈),將用戶的Web請求進行攔截處理,從而提供了更加豐富的功能,例如數據類型轉換、國際化、文件上傳等。圖1.9所示是Struts 2框架結構圖,Struts 2框架中的處理大概分爲以下幾個步驟:
客戶端初始化一個指向Servlet容器(例如Tomcat)的請求。
這個請求經過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對於Struts 2和其他框架的集成很有幫助,例如SiteMesh Plugin)。
接着FilterDispatcher被調用,FilterDispatcher詢問ActionMapper來決定這個請求是否需要調用某個Action。
如果ActionMapper決定需要調用某個Action,FilterDispatcher把請求的處理交給ActionProxy。
ActionProxy通過Configuration Manager詢問框架的配置文件,找到需要調用的Action類。
ActionProxy創建一個ActionInvocation實例。
ActionInvocation實例使用命名模式來調用,回調Action的execute方法,該execute方法先獲取用戶請求參數,然後它會調用業務邏輯組件來處理用戶的請求。在調用Action的過程前後,涉及到相關攔截器(Interceptor)的調用。
一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果通常是(但不總是,也可能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模板。在表示的過程中可以使用Struts 2框架中繼承的標籤。
由於印刷原因,讀者不能夠根據圖上的不同顏色來區分結構。下面使用文字進行介紹。
Servlet Filter:包括ActionContextCleanUp、Other Filters和FilterDispatcher。
Struts Core:Struts核心模塊,包含ActionMapper、標籤庫、ActionProxy、ActionInvocation、Result。
攔截器(Interceptor)。
用戶創建代碼:這部分包含struts.xml、Action、視圖(JSP等)。
從上面的描述讀者可以看到,實現一個Struts應用,只需要配置struts.xml文件、編寫Action代碼和相關視圖資源文件即可。圖1.10所示是Struts 2架構圖,從圖中可以看到,從用戶請求到Action執行,過程中間佈滿了攔截器,這些攔截器可以在Action執行之前或者執行之後來運行。攔截器是Struts 2核心內容之一,後面將會詳細介紹。
★ 說明 ★
Struts 2框架流程圖和WebWork框架流程圖相互比較,讀者會發現兩者極其相似,進一步說明了Struts 2框架是WebWork的升級版本。、
圖1.10 Struts 2架構圖
1.4.2 Struts 2配置文件
Struts 2配置文件是用戶請求(View)和業務邏輯模塊(Model)Action之間聯繫的橋樑,開發者可以通過修改Struts 2的配置文件,來快速適應業務需求,它是整個Struts 2的精髓之一。當然,熟悉Struts 1和WebWork框架的讀者對配置文件一定不會陌生。Struts 2框架配置文件一般可以分爲兩類:struts.xml文件和屬性資源文件。
1.配置Action的struts.xml文件
配置Action的struts.xml文件,也包括用戶自己定義的*.xml文件,然後通過include指令包含到struts.xml文件中。struts.xml文件包含了Action的定義,同時定義了Action返回值對應的視圖資源(result),還有命名空間信息等。
★ 說明 ★
struts.xml文件是Struts 2框架的核心配置文件,開發者可以建立獨立的配置文件,在struts.xml中使用include指令包含進來,後面章節將會做詳細介紹。
(1)代碼1.5就是一個struts.xml的例子。
代碼1.5 配置文件struts.xml示例
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!--開始Struts 2配置-->
<!--配置Struts 2的pachage,Action必須配置在其中-->
<package name="pla" extends="struts-default">
<!--配置Action-->
<action name="login" class="pla.LoginAction">
<!--配置Action的返回值success視圖-->
<result name="success">/welcome.jsp</result>
<!--配置Action的返回值error視圖-->
<result name="error">/ error.jsp</result>
<!--配置Action的返回值input視圖-->
<result name="input">/ input.jsp</result>
</action>
</package>
</struts>
上面配置文件struts.xml中定義了一個Action:
<action name="login" class="pla.LoginAction">
(2)Action名字是“login”,對應的Class就是“pla.LoginAction”,當用戶在瀏覽器輸入http://127.0.0.1/8080/...login.action請求時,Struts 2將調用pla.LoginAction進行業務處理。處理後,返回result值。LoginAction內容如代碼1.6所示。
代碼1.6 業務控制器LoginAction
public class LoginAction {
//設置屬性
private String username,password;
//定義屬性的getter和setter方法
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//Action默認執行方法
public String execute()throws Exception{
if (getUsername().equals("test")){
//返回success字符串
return "success";
}else{
//返回input字符串
return "input";
}
}
}
(3)在Action中,判斷getUsername()是否爲“test”,如果是,則返回字符串"success",而struts.xml配置文件中定義了對應的視圖資源:
<!——配置Action的返回值success視圖-->
<result name="success">/welcome.jsp</result>
可以看到,配置文件定義了result,name元素爲success,對應視圖資源爲/welcome.jsp,那麼當用戶請求參數Username爲“test”時,Struts 2會將/welcome.jsp頁面展示給用戶。
(4)如果系統中還有一個處理Login業務的Action,內容如代碼1.7所示。
代碼1.7 業務控制器LoginAction01
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
public class LoginAction01 implements Action {
//設置屬性
private String username,password;
//定義屬性的getter和setter方法
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//Action默認執行方法
public String execute() throws Exception {
if (getUsername().equals("test")){
//不同於LoginAction的業務實現邏輯
Dosomething();
return "success";
}else{
return "input";
}
}
}
(5)當用戶業務邏輯發生變化時,需要調用LoginAction01來實現,那麼通過修改配置文件,可以非常方便、快捷地進行調整,只需要修改Action中的class屬性即可:
<action name="login" class="pla.LoginAction01">
★ 提示 ★
通過配置文件來調換Action等模塊,類似於靈活的“熱插拔”技術。
2.屬性資源文件
另一類配置文件是屬性資源文件,例如struts.properties文件。資源文件中一般採用固定的Key-Value格式,用於定義Struts 2全局或者局部的資源數據,例如國際化、Struts 2開發模式等信息。Struts.properties文件示例見代碼1.8。
代碼1.8 struts.properties文件示例
#設置字符集
struts.i18n.encoding=UTF-8
#該屬性指定Http的請求後綴
struts.action.extension=do,action
#該屬性設置當struts.xml文件改變後,系統是否自動重新加載該文件
struts.configuration.xml.reload=false
#指定當前應用默認的國際化地區信息
struts.locale=en_us
★ 注意 ★
有過Struts 1.X開發經驗的讀者會發現,Struts 2框架的Action只是一個普通的Java類(POJO),這是同Struts 1.X的重要區別之一。