Struts 2權威指南:基於WebWork核心的MVC開發

轉自:http://blog.csdn.net/Mr_Von/article/details/3020629

1.2  Struts 2的起源和背景

Struts 2以WebWork優秀的設計思想爲核心,吸收了Struts 1的部分優點,建立了一個兼容WebWork和Struts 1的MVC框架,Struts 2的目標是希望可以讓原來使用Struts 1、WebWork的開發人員,都可以平穩過渡到使用Struts 2框架。

1.2.1  Struts 1簡介及存在的問題

從過去的歲月來看,Struts 1是所有MVC框架中不容辯駁的勝利者,不管是市場佔有率,還是所擁有的開發人羣,Struts 1都擁有其他MVC框架不可比擬的優勢。Struts 1的成功得益於它豐富的文檔、活躍的開發羣體。當然,Struts 1是世界上第一個發佈的MVC框架:Struts 1.0在2001年6月發佈,這一點可能是使它得到如此廣泛擁戴的主要原因。

爲了使讀者可以明白Struts 1的運行機制,下面將簡要介紹Struts 1的基本框架。

Struts 1框架以ActionServlet作爲核心控制器,整個應用由客戶端請求驅動。當客戶端向Web應用發送請求時,請求將被Struts 1的核心控制器ActionServlet攔截,ActionServlet根據請求決定是否需要調用業務邏輯控制器處理用戶請求(實際上,業務邏輯控制器還是控制器,它只是負責調用模型來處理用戶請求),當用戶請求處理完成後,其處理結果通過JSP呈現給用戶。

對於整個Struts 1框架而言,控制器就是它的核心,Struts 1的控制器由兩個部分組成:核心控制器和業務邏輯控制器。其中核心控制器就是ActionServlet,由Struts 1框架提供;業務邏輯控制就是用戶自定義的Action,由應用開發者提供。

對於大部分用戶請求而言,都需要得到服務器的處理。當用戶發送一個需要得到服務器處理的請求時,該請求被ActionServlet攔截到,ActionServlet將該請求轉發給對應的業務邏輯控制器,業務邏輯控制器調用模型來處理用戶請求;如果用戶請求只是希望得到某個URL資源,則由ActionServlet將被請求的資源轉發給用戶。

Struts 1的程序運行流程如圖1.7所示。

圖1.7  Struts 1的程序運行流程

下面就Struts 1程序流程具體分析MVC中的三個角色。

(1)Model部分

Struts 1的Model部分主要由底層的業務邏輯組件充當,這些業務邏輯組件封裝了底層數據庫訪問、業務邏輯方法實現。實際上,對於一個成熟的企業應用而言,Model部分也不是一個簡單的JavaBean所能完成的,它可能是一個或多個EJB組件,可能是一個WebService服務。總之,Model部分封裝了整個應用的所有業務邏輯,但整個部分並不是由Struts 1提供的,Struts 1也沒有爲實現Model組件提供任何支持。

(2)View部分

Struts 1的View部分採用JSP實現。Struts 1提供了豐富的標籤庫,通過這些標籤庫可以最大限度地減少腳本的使用。這些自定義的標籤庫可以輸出控制器的處理結果。

雖然Struts 1提供了與Ties框架的整合,但Struts 1所支持的表現層技術非常單一:既不支持FreeMarker、Velocity等模板技術,也不支持JasperReports等報表技術。

(3)Controller部分

Struts 1的Controller由兩個部分組成。

— 系統核心控制器:由Struts 1框架提供,就是系統中的ActionServlet。

— 業務邏輯控制器:由Struts 1框架提供,就是用戶自己實現的Action實例。

Struts 1的核心控制器對應圖1.7中的核心控制器(ActionServlet)。該控制器由Struts 1框架提供,繼承HttpServlet類,因此可以配置成一個標準的Servlet,該控制器負責攔截所有HTTP請求,然後根據用戶請求決定是否需要調用業務邏輯控制器,如果需要調用業務邏輯控制器,則將請求轉發給Action處理,否則直接轉向請求的JSP頁面。

業務邏輯控制器負責處理用戶請求,但業務邏輯控制器本身並不具有處理能力,而是調用Model來完成處理。

Struts 1提供了系統所需要的核心控制器,也爲實現業務邏輯控制器提供了許多支持。因此,控制器部分就是Struts 1框架的核心。有時候,我們直接將MVC層稱爲控制器層。

 提示  對於任何的MVC框架而言,其實只實現了C(控制器)部分,但它負責用控制器調用業務邏輯組件,並負責控制器與視圖技術(JSP、FreeMarker和Velocity等)的整合。

對於Struts 1框架而言,因爲它與JSP/Servlet耦合非常緊密,因而導致了許多不可避免的缺陷,隨着Web應用的逐漸擴大,這些缺陷逐漸變成制約Struts 1發展的重要因素——這也是Struts 2出現的原因。下面具體分析Struts 1中存在的種種缺陷。

(1)支持的表現層技術單一

Struts 1只支持JSP作爲表現層技術,不提供與其他表現層技術,例如Velocity、FreeMarker等技術的整合。這一點嚴重製約了Struts 1框架的使用,對於目前的很多Java EE應用而言,並不一定使用JSP作爲表現層技術。

雖然Struts 1處理完用戶請求後,並沒有直接轉到特定的視圖資源,而是返回一個ActionForward對象(可以理解ActionForward是一個邏輯視圖名),在struts-config.xml文件中定義了邏輯視圖名和視圖資源之間的對應關係,當ActionServlet得到處理器返回的ActionForword對象後,可以根據邏輯視圖名和視圖資源之間的對應關係,將視圖資源呈現給用戶。

從上面的設計來看,不得不佩服Struts 1的設計者高度解耦的設計:控制器並沒有直接執行轉發請求,而僅僅返回一個邏輯視圖名——實際的轉發放在配置文件中進行管理。但因爲Struts 1框架出現的年代太早了,那時候還沒有FreeMarker、Velocity等技術,因而沒有考慮與這些FreeMarker、Velocity等視圖技術的整合。

 提示  Struts 1已經通過配置文件管理邏輯視圖名和實際視圖之間的對應關係,只是沒有做到讓邏輯視圖名可以支持更多的視圖技術。

雖然Struts 1有非常優秀的設計,但由於歷史原因,它沒有提供與更多視圖技術的整合,這嚴重限制了Struts 1的使用。

(2)與Servlet API嚴重耦合,難於測試

因爲Struts 1框架是在Model 2的基礎上發展起來的,因此它完全是基於Servlet API的,所以在Struts 1的業務邏輯控制器內,充滿了大量的Servlet API。

看下面的Action代碼片段:

//業務邏輯控制器必須繼承Struts 1提供的Action類

public class LoginAction extends Action

{

                                 //處理用戶請求的execute方法

                                  public ActionForward execute(ActionMapping mapping, ActionForm form,

                                  HttpServletRequest request, HttpServletResponse response)throws

                                         AuctionException

                                  {

                                    //獲取封裝用戶請求參數的ActionForm對象

                                    //將其強制類型轉換爲登錄用的ActionForm

                                    LoginForm loginForm = (LoginForm)form;

                                    //當用戶名爲scott,密碼爲tiger時返回成功

                                    if ("scott".equals(loginForm.getUsername()

                                        && "tiger".equals(loginForm.getPassword())

                                    {

                                        //處理成功,返回一個ActionForward對象

                                        return mapping.findForward("success");

                                    }

                                    else

                                    {

                                        //處理失敗,返回一個ActionForward對象

                                        return mapping.findForward("success");

                                    }

                                  }

}

當我們需要測試上面Action類的execute方法時,該方法有4個參數:ActionMapping、ActionForm、HttpServletRequest和HttpServletResponse,初始化這4個參數比較困難,尤其是HttpServletRequest和HttpServletResponse兩個參數,通常由Web容器負責實例化。

因爲HttpServletRequest和HttpServletResponse兩個參數是Servlet API,嚴重依賴於Web服務器。因此,一旦脫離了Web服務器,Action的測試非常困難。

(3)代碼嚴重依賴於Struts 1 API,屬於侵入式設計

正如從上面代碼片段中所看到的,Struts 1的Action類必須繼承Struts 1的Action基類,實現處理方法時,又包含了大量Struts 1 API:如ActionMapping、ActionForm和ActionForward類。這種侵入式設計的最大弱點在於,一旦系統需要重構時,這些Action類將完全沒有利用價值,成爲一堆廢品。

可見,Struts 1的Action類這種侵入式設計導致了較低的代碼複用。

1.2.2  WebWork簡介

WebWork雖然沒有Struts 1那樣赫赫有名,但也是出身名門,WebWork來自另外一個優秀的開源組織:opensymphony,這個優秀的開源組織同樣開發了大量優秀的開源項目,如Qutarz、OSWorkFlow等。實際上,WebWork的創始人則是另一個Java領域的名人:Rickard Oberg(他就是JBoss和XDoclet的作者)。

相對於Struts 1存在的那些先天性不足而言,WebWork則更加優秀,它採用了一種更加鬆耦合的設計,讓系統的Action不再與Servlet API耦合。使單元測試更加方便,允許系統從B/S結構向C/S結構轉換。

相對於Struts 1僅支持JSP表現層技術的缺陷而言,WebWork支持更多的表現層技術,如Velocity、FreeMarker和XSLT等。

WebWork可以脫離Web應用使用,這一點似乎並沒有太多優勢,因爲,一個應用通常開始已經確定在怎樣的環境下使用。WebWork有自己的控制反轉(Inversion of Control)容器,通過控制反轉,可以讓測試變得更簡單,測試中設置實現服務接口的Mock對象完成測試,而不需要設置服務註冊。

WebWork 2使用OGNL這個強大的表達式語言,可以訪問值棧。OGNL對集合和索引屬性的支持非常強大。

WebWork建立在XWork之上,使用ServletDispatcher作爲該框架的核心控制器,處理HTTP的響應和請求。

從處理流程上來看,WebWork與Struts 1非常類似,它們的核心都由控制器組成,其中控制器都由兩個部分組成:

— 核心控制器ServletDispatcher,該控制器框架提供。

— 業務邏輯控制器Action,該控制器由程序員提供。

相對Struts 1的Action與Servlet API緊緊耦合的弱點來說,WebWork的Action則完全與Servlet API分離,因而該Action更容易測試。

WebWork的Action可以與Servlet API分離,得益於它靈巧的設計,它使用一個攔截器鏈,負責將用戶請求數據轉發到Action,並負責將Action的處理結果轉換成對用戶的響應。

當用戶向Web應用發送請求時,該請求經過ActionContextCleanUp、SiteMesh等過濾器過濾,由WebWork的核心控制器攔截,如果用戶請求需要WebWork的業務邏輯控制器處理,該控制器則調用Action映射器,該映射器將用戶請求轉發到對應的業務邏輯控制器。值得注意的是,此時的業務邏輯控制器並不是開發者實現的控制器,而是WebWork創建的控制器代理。

創建控制器代理時,WebWork需要得到開發者定義的xwork.xml配置文件,控制器代理以用戶實現的控制器作爲目標,以攔截器鏈中的攔截器作爲處理(Advice)。

 提示  WebWork中創建控制器代理的方式,就是一種AOP(面向切面編程)編程方式,只是這種AOP中的攔截器由系統提供,因此無需用戶參與。如果讀者需要獲取更多關於AOP編程的知識,請參閱AOP相關資料,或筆者所著的《Spring 2.0寶典》一書的第6章。

開發者自己實現的業務邏輯控制器只是WebWork業務控制器的目標——這就是爲什麼開發者自己實現的Action可以與Servlet API分離的原因。當開發者自己的Action處理完HTTP請求後,該結果只是一個普通字符串,該字符串將對應到指定的視圖資源。

指定的試圖資源經過攔截器鏈的處理後,生成對客戶端的響應輸出。

上面整個過程的數據流圖如圖1.8所示。

與前面的Struts 1框架對比,不難發現WebWork在很多地方確實更優秀。相對Struts 1的種種缺點而言,WebWork存在如下優點:

圖1.8  WebWork的數據流圖

(1)Action無需與Servlet API耦合,更容易測試

相對於Struts 1框架中的Action出現了大量Servlet API而言,WebWork的Action更像一個普通Java對象,該控制器代碼中沒有耦合任何Servlet API。看下面的WebWork的Action示例:

public class LoginAction implements Action

{

                                 //該字符串常量將作爲Action的返回值

                                  private final static String LOGINFAIL="loginfail";

                                 //該Action封裝的兩個請求參數

                                  private String password;

                                 private String username;

                                 //password請求參數對應的getter方法

                                  public String getPassword()

                                  {

                                  return password;

                                  }

                                 //password請求參數對應的setter方法

                                  public void setPassword(String password)

                                  {

                                  this.password = password;

                                  }

                                 //username請求參數對應的getter方法

                                  public String getUsername()

                                  {

                                  return username;

                                  }

                                 //username請求參數對應的setter方法

                                  public void setUsername(String username)

                                  {

                                  this.username = username;

                                  }

                                 //處理用戶請求的execute方法

                                  public String execute() throws Exception

                                  {

                                  if ("yeeku".equalsIgnoreCase(getUsername())

                                     && "password".equals(getPassword()))

                                  {

                                   ActionContext ctx = ActionContext.getContext();

                                   //將當前登錄的用戶名保存到Session

                                   Map session = ctx.getSession();

                                   session.put("username",getUsername());

                                   return SUCCESS;

                                  }

                                  else

                                  {

                                   return LOGINFAIL;

                                  }

                                  }

}

在上面的Action代碼中,我們看不到任何的Servlet API,當系統需要處理兩個請求參數:username和password時,Action並未通過HttpServletRequest對象來獲得請求參數,而是直接調用訪問該Action的username和password成員屬性——這兩個屬性由Action攔截器負責初始化,以用戶請求參數爲其賦值。

即使Action中需要訪問HTTP Session對象,依然沒有在代碼中直接出現HttpSession API,而是以一個Map對象代表了HTTP Session對象。

當我們將WebWork的Action和Struts 1的Action進行對比時,不難發現Struts 1的Action確實太臃腫了,確實不如WebWork的Action那麼優雅。

如果需要測試上面的Action代碼,測試用例的書寫將非常容易,因爲execute方法中沒有包含任何Servlet API,甚至沒有WebWork的API。

(2)Action無需與WebWork耦合,代碼重用率高

在上面的Action代碼中,不難發現WebWork中的Action其實就是一個POJO,該Action僅僅實現了WebWork的Action接口,包含了一個execute方法。

Struts 1中的Action類需要繼承Struts 1的Action類。我們知道,實現一個接口和繼承一個類是完全不同的概念:實現一個接口對類的污染要小得多,該類也可以實現其他任意接口,還可以繼承一個父類;但一旦已經繼承一個父類,則意味着該類不能再繼承其他父類。

除此之外,Struts 1中Action也包含了一個execute方法,但該方法需要4個參數,類型分別是ActionMapping、ActionForm、HttpServletRequest和HttpServletResponse,一個包含了這4個參數的方法,除了在Struts 1框架下有用外,筆者難以想象出該代碼還有任何複用價值。但WebWork的execute方法則完全不同,該方法中沒有出現任何Servlet API,也沒有出現任何WebWork API,這個方法在任何環境下都有重用的價值。

得益於WebWork靈巧的設計,WebWork中的Action無需與任何Servlet API、WebWork API耦合,從而具有更好的代碼重用率。

(3)支持更多的表現層技術,有更好的適應性

正如從圖1.8所見到的,WebWork對多種表現層技術:JSP、Velocity和FreeMarker等都有很好的支持,從而給開發更多的選擇,提供了更好的適應性。

1.2.3  Struts 2起源

經過五年多的發展,Struts 1已經成爲一個高度成熟的框架,不管是穩定性還是可靠性,都得到了廣泛的證明。但由於它太“老”了,一些設計上的缺陷成爲它的硬傷。面對大量新的MVC框架蓬勃興起,Struts 1也開始了血液的更新。

目前,Struts已經分化成兩個框架:第一個框架就是傳統Struts 1和WebWork結合後的Struts 2框架。Struts 2雖然是在Struts 1的基礎上發展起來的,但實質上是以WebWork爲核心,Struts 2爲傳統Struts 1注入了WebWork的設計理念,統一了Struts 1和WebWork兩個框架,允許Struts 1和WebWork開發者同時使用Struts 2框架。

Struts分化出來的另外一個框架是Shale,這個框架遠遠超出了Struts 1原有的設計思想,它與原有的Struts 1的關聯很少,它使用全新的設計思想。Shale更像一個新的框架,而不是Struts的升級。Shale 在很多方面與Struts存在不同之處,其中有兩點最爲突出:

—  Struts與JSF集成,而Shale則是建立在JSF之上。

—  Struts實質上是一個巨大的、複雜的請求處理器;而Shale則是一組能以任何方式進行組合的服務,簡單地說,Shale是一種SOA(面向服務架構)架構。

在後面的介紹中,我們會發現,Struts 2非常類似於WebWork框架,而不像Struts 1框架,因爲Struts 2是以WebWork爲核心,而不是以Struts 1爲核心的。正因爲此,許多WebWork開發者會發現,從WebWork過渡到Struts 2是一件非常簡單的事情。

當然,對於傳統的Struts 1開發者,Struts 2也提供了很好的向後兼容性,Struts 2可與Struts 1有機整合,從而保證Struts 1開發者能平穩過渡到Struts 2。

1.3  Struts 2體系介紹

Struts 2的體系與Struts 1體系的差別非常大,因爲Struts 2使用了WebWork的設計核心,而不是使用Struts 1的設計核心。Struts 2大量使用攔截器來處理用戶請求,從而允許用戶的業務邏輯控制器與Servlet API分離。

1.3.1  Struts 2框架架構

從數據流圖上來看,Struts 2與WebWork相差不大,Struts 2同樣使用攔截器作爲處理(Advice),以用戶的業務邏輯控制器爲目標,創建一個控制器代理。

控制器代理負責處理用戶請求,處理用戶請求時回調業務控制器的execute方法,該方法的返回值將決定了Struts 2將怎樣的視圖資源呈現給用戶。

圖1.9顯示了Struts 2的體系概圖。

圖1.9  Struts 2的體系概圖

Struts 2框架的大致處理流程如下:

 瀏覽器發送請求,例如請求/mypage.action、/reports/myreport.pdf等。

 核心控制器FilterDispatcher根據請求決定調用合適的Action。

 WebWork的攔截器鏈自動對請求應用通用功能,例如workflow、validation或文件上傳等功能。

 回調Action的execute方法,該execute方法先獲取用戶請求參數,然後執行某種數據庫操作,既可以是將數據保存到數據庫,也可以從數據庫中檢索信息。實際上,因爲Action只是一個控制器,它會調用業務邏輯組件來處理用戶的請求。

 Action的execute方法處理結果信息將被輸出到瀏覽器中,可以是HTML頁面、圖像,也可以是PDF文檔或者其他文檔。此時支持的視圖技術非常多,既支持JSP,也支持Velocity、FreeMarker等模板技術。

1.3.2  Struts 2的配置文件

當Struts 2創建系統的Action代理時,需要使用Struts 2的配置文件。

Struts 2的配置文件有兩份:

— 配置Action的struts.xml文件。

— 配置Struts 2全局屬性的struts.properties文件。

struts.xml文件內定義了Struts 2的系列Action,定義Action時,指定該Action的實現類,並定義該Action處理結果與視圖資源之間的映射關係。

下面是struts.xml配置文件的示例:

<struts>

                                 <!-- Struts 2的Action都必須配置在package裏 -->

                                 <package name="default" extends="struts-default">

                                    <!-- 定義一個Logon的Action,實現類爲lee.Logon -->

                                  <action name="Logon" class="lee.Logon">

                                        <!-- 配置Action返回input時轉入/pages/Logon.jsp頁面 -->

                                   <result name="input">/pages/Logon.jsp</result>

                                        <!-- 配置Action返回cancel時重定向到Welcome的Action-->

                                   <result name="cancel" type="redirect-action">Welcome</result>

                                        <!-- 配置Action返回success時重定向到MainMenu的Action -->

                                   <result type="redirect-action">MainMenu</result>

                                        <!-- 配置Action返回expired時進入ChangePassword的Action鏈 -->

                                   <result name="expired" type="chain">ChangePassword</result>

                                  </action>

                                    <!-- 定義Logoff的Action,實現類爲lee.Logoff -->

                                  <action name="Logoff" class=" lee.Logoff">

                                        <!-- 配置Action返回success時重定向到MainMenu的Action -->

                                   <result type="redirect-action">Welcome</result>

                                  </action>

    </package>

</struts>

在上面的struts.xml文件中,定義了兩個Action。定義Action時,不僅定義了Action的實現類,而且的定義Action的處理結果時,指定了多個result,result元素指定execute方法返回值和視圖資源之間的映射關係。對於如下配置片段:

<result name="cancel" type="redirect-action">Welcome</result>

表示當execute方法返回cancel的字符串時,跳轉到Welcome的Action。定義result元素時,可以指定兩個屬性:type和name。其中name指定了execute方法返回的字符串,而type指定轉向的資源類型,此處轉向的資源可以是JSP,也可以是FreeMarker等,甚至是另一個Action——這也是Struts 2可以支持多種視圖技術的原因。

除此之外,Struts 2還有一個配置Struts 2全局屬性的Properties文件:struts.properties。該文件的示例如下:

#指定Struts 2處於開發狀態

struts.devMode = false

//指定當Struts 2配置文件改變後,Web框架是否重新加載Struts 2配置文件

struts.configuration.xml.reload=true

正如上面見到的,struts.properties文件的形式是系列的key、value對,它指定了Struts 2應用的全局屬性。

1.3.3  Strut 2的標籤庫

Struts 2的標籤庫也是Struts 2的重要組成部分,Struts 2的標籤庫提供了非常豐富的功能,這些標籤庫不僅提供了表現層數據處理,而且提供了基本的流程控制功能,還提供了國際化、Ajax支持等功能。

通過使用Struts 2的標籤,開發者可以最大限度地減少頁面代碼的書寫。

看下面的JSP頁面的表單定義片段:

<!--  定義一個Action -->

<form method="post" action="basicvalid.action">

                                 <!-- 下面定義三個表單域 -->

    名字:<input type="text" name="name"/><br>

    年紀:<input type="text" name="age"/><br>

    喜歡的顏色:<input type="text" name="favorite"/><br>

                                 <!-- 定義一個輸出按鈕 -->

    <input type="submit" value="提交"/>

</form>

上面頁面使用了傳統的HTML標籤定義表單元素,還不具備輸出校驗信息的功能,但如果換成如下使用Struts 2標籤的定義方式:

<!-- 使用Struts 2標籤定義一個表單 -->

<s:form method="post" action="basicvalid.action">

                                 <!-- 下面使用Struts 2標籤定義三個表單域 -->

                                  <s:textfield label="名字" name="name"/>

                                  <s:textfield label="年紀" name="age"/>

                                  <s:textfield label="喜歡的顏色" name="answer"/>

                                 <!-- 定義一個提交按鈕 -->

                                  <s:submit/>

</s:form>

則頁面代碼更加簡潔,而且有更簡單的錯誤輸出。圖1.10是上面使用Struts 2標籤執行數據校驗後的輸出。

圖1.10  使用Struts 2標籤的效果

 提示  Struts 2的標籤庫的功能非常複雜,該標籤庫幾乎可以完全替代JSTL的標籤庫。而且Struts 2的標籤支持表達式語言,這種表達式語言支持一個強大和靈活的表達式語言:OGNL(Object Graph Notation Language),因此功能非常強大。

1.3.4  Struts 2的控制器組件

Struts 2的控制器組件是Struts 2框架的核心,事實上,所有MVC框架都是以控制器組件爲核心的。正如前面提到的,Struts 2的控制器由兩個部分組成:FilterDispatcher和業務控制器Action。

實際上,Struts 2應用中起作用的業務控制器不是用戶定義的Action,而是系統生成的Action代理,但該Action代理以用戶定義的Action爲目標。

下面是Struts 2的Action代碼示例:

 

  1. public class LoginAction
  2. {
  3.                                  //封裝用戶請求參數的username屬性
  4.                                  private String username;
  5.                                  //封裝用戶請求參數的password屬性
  6.                                   private String password;
  7.                                  //username屬性的getter方法
  8.                                   public String getUsername()
  9.                                  {
  10.                                   return username;
  11.                                   }
  12.                                  //username屬性的setter方法
  13.                                   public void setUsername(String username)
  14.                                  {
  15.                                   this.username = username;
  16.                                   }
  17.                                  //password屬性的getter方法
  18.                                   public String getPassword()
  19.                                  {
  20.         return password;
  21.     }
  22.                                  //password屬性的setter方法
  23.                                   public void setPassword(String password)
  24.                                  {
  25.                                   this.password = password;
  26.                                   }
  27.                                  //處理用戶請求的execute方法
  28.                                   public String execute() throws Exception
  29.                                  {
  30.                                     //如果用戶名爲scott,密碼爲tiger,則登錄成功
  31.                                   if (getUsername().equals("scott")
  32.                                      && getPassword().equals("tiger") )
  33.                                     {
  34.                                    return "success";
  35.                                   }
  36.                                     else
  37.                                     {
  38.                                    return "error";
  39.                                   }
  40.                                   }
  41. }

通過查看上面的Action代碼,發現該Action比WebWork中的Action更徹底,該Action無需實現任何父接口,無需繼承任何Struts 2基類,該Action類完全是一個POJO(普通、傳統的Java對象),因此具有很好的複用性。

歸納起來,該Action類有如下優勢:

—  Action類完全是一個POJO,因此具有很好的代碼複用性。

—  Action類無需與Servlet API耦合,因此進行單元測試非常簡單。

—  Action類的execute方法僅返回一個字符串作爲處理結果,該處理結果可映射到任何的視圖,甚至是另一個Action。

1.4  Struts 2與Struts 1的對比

經過上面簡要介紹,不難發現,Struts 2確實在Struts 1上做出了巨大的改進,的確是一個非常具有實用價值的MVC框架。下面是Struts 1和Struts 2在各方面的簡要對比。

— 在Action實現類方面的對比:Struts 1要求Action類繼承一個抽象基類;Struts 1的一個具體問題是使用抽象類編程而不是接口。Struts 2 Action類可以實現一個Action接口,也可以實現其他接口,使可選和定製的服務成爲可能。Struts 2提供一個ActionSupport基類去實現常用的接口。即使Action接口不是必須實現的,只有一個包含execute方法的POJO類都可以用作Struts 2的Action。

— 線程模式方面的對比:Struts 1 Action是單例模式並且必須是線程安全的,因爲僅有Action的一個實例來處理所有的請求。單例策略限制了Struts 1 Action能做的事,並且要在開發時特別小心。Action資源必須是線程安全的或同步的;Struts 2 Action對象爲每一個請求產生一個實例,因此沒有線程安全問題。

—  Servlet依賴方面的對比:Struts 1 Action依賴於Servlet API,因爲Struts 1 Action的execute方法中有HttpServletRequest和HttpServletResponse方法。Struts 2 Action不再依賴於Servlet API,從而允許Action脫離Web容器運行,從而降低了測試Action的難度。 當然,如果Action需要直接訪問HttpServletRequest和HttpServletResponse參數,Struts 2 Action仍然可以訪問它們。但是,大部分時候,Action都無需直接訪問HttpServetRequest和HttpServletResponse,從而給開發者更多靈活的選擇。

— 可測性方面的對比:測試Struts 1 Action的一個主要問題是execute方法依賴於Servlet API,這使得Action的測試要依賴於Web容器。爲了脫離Web容器測試Struts 1的Action,必須藉助於第三方擴展:Struts TestCase,該擴展下包含了系列的Mock對象(模擬了HttpServetRequest和HttpServletResponse對象),從而可以脫離Web容器測試Struts 1的Action類。Struts 2 Action可以通過初始化、設置屬性、調用方法來測試。

— 封裝請求參數的對比:Struts 1使用ActionForm對象封裝用戶的請求參數,所有的ActionForm必須繼承一個基類:ActionForm。普通的JavaBean不能用作ActionForm,因此,開發者必須創建大量的ActionForm類封裝用戶請求參數。雖然Struts 1提供了動態ActionForm來簡化ActionForm的開發,但依然需要在配置文件中定義ActionForm;Struts 2直接使用Action屬性來封裝用戶請求屬性,避免了開發者需要大量開發ActionForm類的煩瑣,實際上,這些屬性還可以是包含子屬性的Rich對象類型。如果開發者依然懷念Struts 1 ActionForm的模式,Struts 2提供了ModelDriven模式,可以讓開發者使用單獨的Model對象來封裝用戶請求參數,但該Model對象無需繼承任何Struts 2基類,是一個POJO,從而降低了代碼污染。

— 表達式語言方面的對比:Struts 1整合了JSTL,因此可以使用JSTL表達式語言。這種表達式語言有基本對象圖遍歷,但在對集合和索引屬性的支持上則功能不強;Struts 2可以使用JSTL,但它整合了一種更強大和靈活的表達式語言:OGNL(Object Graph Notation Language),因此,Struts 2下的表達式語言功能更加強大。

— 綁定值到視圖的對比:Struts 1使用標準JSP機制把對象綁定到視圖頁面;Struts 2使用“ValueStack”技術,使標籤庫能夠訪問值,而不需要把對象和視圖頁面綁定在一起。

— 類型轉換的對比:Struts 1 ActionForm 屬性通常都是String類型。Struts 1使用Commons-Beanutils進行類型轉換,每個類一個轉換器,轉換器是不可配置的;Struts 2使用OGNL進行類型轉換,支持基本數據類型和常用對象之間的轉換。

— 數據校驗的對比:Struts 1支持在ActionForm重寫validate方法中手動校驗,或者通過整合Commons alidator框架來完成數據校驗。Struts 2支持通過重寫validate方法進行校驗,也支持整合XWork校驗框架進行校驗。

—  Action執行控制的對比:Struts 1支持每一個模塊對應一個請求處理(即生命週期的概念),但是模塊中的所有Action必須共享相同的生命週期。Struts 2支持通過攔截器堆棧(Interceptor Stacks)爲每一個Action創建不同的生命週期。開發者可以根據需要創建相應堆棧,從而和不同的Action一起使用。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章