翻譯:SpringSide團隊? ?轉載請注明出處。
? ???有很多人都很熟悉 Struts, 無論是從項目中直接獲得的實戰經驗還是從書中了解到的。我們這一系列文章,將通過一個由 Stuts 轉移到 Struts2 簡單的例子向大家展現Struts2的所有特征。
? ? 在我們開始這個例子之前,你需要去知道一點 Struts2的背景知識。 在第一部分的文章中,我們將介紹Struts2與Struts的核心框架的不同點,以助于更好地了解其他方面的整合。第二部分中,我們將深入探討 actions 的差別, action相關的框架特征,和action配置。在最后一部分中,我們將會講述 user interface,我們也會講到其架構,UI構件,themes 和標簽。 還有如何為你的應用加上新的外觀。
? ? 我們并不打算談及遷移過程的所有細節方面,我們只是從出發點開始介紹Struts2 的概念和現在可用的所有特征。但擁有這些知識,你將在以后Struts2的應用中無往而不利。
? ?
Struts的歷史
? ? Struts的第一個版本 是在 2001年5月份發布。它提供了一個Web應用的解決方案,如何讓 JSPs 和 servlets 共存去提供清晰的分離視圖和業務和應用邏輯的架構。在Struts之前,最通常的做法是在JSP中加入業務和應用邏輯,或者在servlets中生成視圖。
? ? 自從第一個版本的發布, Struts 實際上已成為業界公認的Web應用標準。但隨著時間的推移,Web應用框架經常變化的需求,產生了幾個下一代 Struts的解決方案。其中兩個可選方案是Shale 和 Struts Ti。 Shale 是一個基于構建的框架,并在最近成為 Apache 中的重要項目。而 Struts Ti 則是繼續堅持 MVC模式的基礎上改進,繼續Struts的成功經驗。
? ? WebWork項目是在2002年3月發布的,它對Struts式框架進行了革命性改進,引進了不少新的思想,概念和功能,但和原Struts代碼并不兼容。WebWork是一個成熟的框架,經過了好幾次重大的改進與發布。在2005年12月,WebWork與Struts Ti決定合拼, 再此同時, Struts Ti 改名為 Struts Action Framework 2.0,成為Struts真正的下一代。
請求如何運作
? ? 在我們開始詳細探討如何轉移Struts到Struts2之前,讓我們來看看整個請求流程在新架構中是如何運作的。你會注意到在整個請求的生命周期,仍是以controller作主體,而且所有的概念還都是你以前所熟悉的, 就如:

整個請求過程可以分為六步驟:
配置框架
首先最重要的是,讓框架能通過web.xml在servlet containers里運行。
下面這個就是大家都熟悉的 Struts在 web.xml里的配置方法
在 Struts2 中,這個有少許改變,最明顯的是dispatcher 由servlet轉為servlet filter, 其配置和servlet一樣簡單,如下:
和servlet配置一樣,filter配置定義了名稱(供關聯)和filter的類。filter mapping讓URI匹配成功的的請求調用該filter。默認情況下,擴展名為".action"。
這個是在default.properties文件里的"struts.action.extension" 屬性定義的。
在上面介紹的請求運作流程中,我們談及了一些Struts和Struts2的不同點。現在我們將較深入地探討這兩個框架中action結構的具體差別。
讓我們來回顧一下 Struts 的 action 結構, 主要的形式如下:
當實現一個Struts action時, 你需要注意一下問題:
首先你會注意到的是,Struts2中的action不再繼承于任何類或需要實現任何接口。實際上,它還遠不只這些。按照慣例,只有"execute"方法能調用action, 但在Struts2中并非必要,任何聲明為public String methodName() 方法都能通過配置來調用action.
另外,你會注意到返回值不再是"ActionForward ",而是String, 如果你需喜歡String的形式,那在Action接口里有個幫助方法可以提供簡單的結果常量,如"success", "none", "error", "input" 和 "login"。
最后,和Struts最大的革命性的不同是, 調用action不再是帶參數的。那你如何在獲得你所需要的值呢?答案是"inversion of control" 或 "dependency injection", 反轉控制(想了解更多可以看Martin Fowler的文章 http://www.martinfowler.com/articles/injection.html)。
為了更好地了解反轉控制,讓我們來看看一個例子,如何在action處理過程中可以訪問到HttpServerRequest 。在我們的例子中,我們用ServletRequestAware 接口,這個接口包含了相應屬性的setter,如下
當我們繼承這個接口時,我們需要通過setter為我們的HttpServerRequest 屬性變量賦值:
看起來現在這些屬性是類級別的,并不是線程安全的,但是在Struts2里并沒有問題,因為每個請求過來的時候都會產生一個新的action對象實例,它并沒有和其他請求共享一個對象,所以不需要考慮線程安全問題。
現在我們還有最后一步,就是把action關聯上ServletConfigInterceptor 攔截器。這個攔截器繼承了ServletRequestAware 接口,并提供了把HttpServletRequest 注入到action中的功能。但是你現在不用擔心如何配置這些,我們將在下一篇文章中具體講述。最重要的是我們明白了攔截器和接口共同為action提供了反轉控制的功能。
這個設計的好處是能讓action完全和框架解耦。action僅僅是一個被框架使用的簡單的POJO。這對于單元測試但來極大的好處, 你能方便的為Struts action實現 StrutsTestCase 或??MockStrutsTestCase 單元測試。
總結
By到現在為止,你應該已經了解了Struts2的整個請求流程,還有高層的框架概念, 你也應該能自己動手配置Struts2的action,和講出Struts和Struts2的差別了。
在下篇文章中,我們將會介紹一個詳細的Struts應用向Struts2遷移的例子,同時我們也會介紹遷移中相關的知識,會講述如何綜合使用JSTL, JSP 和 Struts2,進一步講述Struts和Struts2的action的差別,Struts2的配置和其他框架元素,和談到更多的其他相關框架的特征。
(自http://www.infoq.com/, cac 翻譯)
? ???有很多人都很熟悉 Struts, 無論是從項目中直接獲得的實戰經驗還是從書中了解到的。我們這一系列文章,將通過一個由 Stuts 轉移到 Struts2 簡單的例子向大家展現Struts2的所有特征。
? ? 在我們開始這個例子之前,你需要去知道一點 Struts2的背景知識。 在第一部分的文章中,我們將介紹Struts2與Struts的核心框架的不同點,以助于更好地了解其他方面的整合。第二部分中,我們將深入探討 actions 的差別, action相關的框架特征,和action配置。在最后一部分中,我們將會講述 user interface,我們也會講到其架構,UI構件,themes 和標簽。 還有如何為你的應用加上新的外觀。
? ? 我們并不打算談及遷移過程的所有細節方面,我們只是從出發點開始介紹Struts2 的概念和現在可用的所有特征。但擁有這些知識,你將在以后Struts2的應用中無往而不利。
? ?
Struts的歷史
? ? Struts的第一個版本 是在 2001年5月份發布。它提供了一個Web應用的解決方案,如何讓 JSPs 和 servlets 共存去提供清晰的分離視圖和業務和應用邏輯的架構。在Struts之前,最通常的做法是在JSP中加入業務和應用邏輯,或者在servlets中生成視圖。
? ? 自從第一個版本的發布, Struts 實際上已成為業界公認的Web應用標準。但隨著時間的推移,Web應用框架經常變化的需求,產生了幾個下一代 Struts的解決方案。其中兩個可選方案是Shale 和 Struts Ti。 Shale 是一個基于構建的框架,并在最近成為 Apache 中的重要項目。而 Struts Ti 則是繼續堅持 MVC模式的基礎上改進,繼續Struts的成功經驗。
? ? WebWork項目是在2002年3月發布的,它對Struts式框架進行了革命性改進,引進了不少新的思想,概念和功能,但和原Struts代碼并不兼容。WebWork是一個成熟的框架,經過了好幾次重大的改進與發布。在2005年12月,WebWork與Struts Ti決定合拼, 再此同時, Struts Ti 改名為 Struts Action Framework 2.0,成為Struts真正的下一代。
請求如何運作
? ? 在我們開始詳細探討如何轉移Struts到Struts2之前,讓我們來看看整個請求流程在新架構中是如何運作的。你會注意到在整個請求的生命周期,仍是以controller作主體,而且所有的概念還都是你以前所熟悉的, 就如:
- 通過URL請求的參數來調用Actions來把數據傳給server.
- 所有的Servlet objects (request, response, session,之類.) 仍然可以在Action中獲取

整個請求過程可以分為六步驟:
- 一個請求產生并經由框架處理 - 框架根據請求匹配相應的配置,如使用哪些攔截器,action 類和結果。
- 請求通過一系列的攔截器 - 攔截器,和攔截器組經配置后,能處理不同等級的請求,它們為請求提供了各種預處理,切面處理。這和Struts的使用 Jakarta Commons Chain 構件的 RequestProcessor類很相似。
- 調用 Action - 產生一個新的action對象實例,并提供請求所調用的處理邏輯的方法。Struts2 可以在配置action時為請求分配其指定的方法。我們在第二部文章中將對這步驟進行進一步討論;
- 調用產生的結果 - 獲取通過action的方法處理后返回來的結果,匹配其result class并調用產生的實例。有種情況是在UI模板去生成HTML時才去處理這些結果。如果在這種情況下,在Struts2 模板中的tags能直接返回到 action 中,取結果來呈現界面。
- 請求再次經過一系列的攔截器處理后返回 - 請求反順序通過與原來進入時的攔截器鏈, 當然,你也可以配置在這個過程中減少或增加攔截器處理.
- 請求返回到用戶 - 最后一步是由 control 返回到servlet。通常是生成HTML返回到user, 但你也可以指定返回的HTTP頭或HTTP重定向。
配置框架
首先最重要的是,讓框架能通過web.xml在servlet containers里運行。
下面這個就是大家都熟悉的 Struts在 web.xml里的配置方法
CODE:
? ?
<servlet>
? ?? ???<servlet-name>action</servlet-name>
? ?? ???<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
? ?? ???<init-param>
? ?? ?? ?? ?<param-name>config</param-name>
? ?? ?? ?? ?<param-value>/WEB-INF/struts-config.xml</param-value>
? ?? ???</init-param>
? ?? ???<load-on-startup>2</load-on-startup>
? ? </servlet>
? ? <servlet-mapping>
? ?? ???<servlet-name>action</servlet-name>
? ?? ???<url-pattern>*.do</url-pattern>
? ? </servlet-mapping>
<servlet>
? ?? ???<servlet-name>action</servlet-name>
? ?? ???<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
? ?? ???<init-param>
? ?? ?? ?? ?<param-name>config</param-name>
? ?? ?? ?? ?<param-value>/WEB-INF/struts-config.xml</param-value>
? ?? ???</init-param>
? ?? ???<load-on-startup>2</load-on-startup>
? ? </servlet>
? ? <servlet-mapping>
? ?? ???<servlet-name>action</servlet-name>
? ?? ???<url-pattern>*.do</url-pattern>
? ? </servlet-mapping>
在 Struts2 中,這個有少許改變,最明顯的是dispatcher 由servlet轉為servlet filter, 其配置和servlet一樣簡單,如下:
CODE:
? ?
<filter>
? ?? ??? <filter-name>webwork</filter-name>
? ?? ??? <filter-class>
? ?? ?? ?? ?org.apache.struts.action2.dispatcher.FilterDispatcher
</filter-class>
? ? </filter>
? ? <filter-mapping>
<filter-name>webwork</filter-name>
<url-pattern>/*</url-pattern>
? ? </filter-mapping>
<filter>
? ?? ??? <filter-name>webwork</filter-name>
? ?? ??? <filter-class>
? ?? ?? ?? ?org.apache.struts.action2.dispatcher.FilterDispatcher
</filter-class>
? ? </filter>
? ? <filter-mapping>
<filter-name>webwork</filter-name>
<url-pattern>/*</url-pattern>
? ? </filter-mapping>
和servlet配置一樣,filter配置定義了名稱(供關聯)和filter的類。filter mapping讓URI匹配成功的的請求調用該filter。默認情況下,擴展名為".action"。
這個是在default.properties文件里的"struts.action.extension" 屬性定義的。
工具箱:??"default.properties"是配置選項定義文件。通過在classpath中包含一個叫"struts.properties"的文件,并設置不同的屬性值,你可以覆蓋這個默認的配置,實現自己的配置。對于Struts, servlet配置提供了初始化tag的參數和使用的文件,而Struts2沒有這樣的配置參數,取而代之的是在classpath下的默認配置文件"struts.xml"。
工具箱/提示: Struts actions(擴展名".do"),Struts2 actions(擴展名".action"),所以Struts和Struts2可以在一個系統中共存。所以最好是保持原先的系統,在新功能的開發上用Struts2, 如果時間和資源允許的情況下再逐步遷移。另一種方法是只是把Struts2的擴展名改為".do",可重用JSPs.分析Actions
在上面介紹的請求運作流程中,我們談及了一些Struts和Struts2的不同點。現在我們將較深入地探討這兩個框架中action結構的具體差別。
讓我們來回顧一下 Struts 的 action 結構, 主要的形式如下:
CODE:
public class MyAction extends Action {
? ? public ActionForward execute(ActionMapping mapping,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?ActionForm form,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?HttpServletRequest request,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?HttpServletResponse response)
? ?? ?? ?? ?throws Exception {
? ?? ???// do the work
? ?? ???return (mapping.findForward("success"));
? ? }
}
? ? public ActionForward execute(ActionMapping mapping,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?ActionForm form,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?HttpServletRequest request,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?HttpServletResponse response)
? ?? ?? ?? ?throws Exception {
? ?? ???// do the work
? ?? ???return (mapping.findForward("success"));
? ? }
}
當實現一個Struts action時, 你需要注意一下問題:
- 所有的action 都必須繼承于base Action 類.
- 所有的action都必須是線程安全的,因為action是單例的,singleton的.
- 因為所有的action都必須是線程安全的,所以所有的對象都不能是類屬性, 都必須以方法參數的形式傳值。
- 調用action的方法必須命名為 "execute" ( 在Struts中的??DispatchAction 類好像可以用其它方法去執行同一個action ,但實際上在框架中調用的仍然是 "execute" 方法。).
- ActionForward 的結果是通過ActionMapping 類中的方法來產生的,通常是"findForward"方法.
CODE:
public class MyAction {
? ?public String execute() throws Exception {
? ?? ???// do the work
? ?? ???return "success";
? ?}
}
? ?public String execute() throws Exception {
? ?? ???// do the work
? ?? ???return "success";
? ?}
}
首先你會注意到的是,Struts2中的action不再繼承于任何類或需要實現任何接口。實際上,它還遠不只這些。按照慣例,只有"execute"方法能調用action, 但在Struts2中并非必要,任何聲明為public String methodName() 方法都能通過配置來調用action.
另外,你會注意到返回值不再是"ActionForward ",而是String, 如果你需喜歡String的形式,那在Action接口里有個幫助方法可以提供簡單的結果常量,如"success", "none", "error", "input" 和 "login"。
最后,和Struts最大的革命性的不同是, 調用action不再是帶參數的。那你如何在獲得你所需要的值呢?答案是"inversion of control" 或 "dependency injection", 反轉控制(想了解更多可以看Martin Fowler的文章 http://www.martinfowler.com/articles/injection.html)。
為了更好地了解反轉控制,讓我們來看看一個例子,如何在action處理過程中可以訪問到HttpServerRequest 。在我們的例子中,我們用ServletRequestAware 接口,這個接口包含了相應屬性的setter,如下
CODE:
public interface ServletRequestAware {
? ? public void setServletRequest(HttpServletRequest request);
}
? ? public void setServletRequest(HttpServletRequest request);
}
當我們繼承這個接口時,我們需要通過setter為我們的HttpServerRequest 屬性變量賦值:
CODE:
public class MyAction implements ServletRequestAware {
? ?private HttpServletRequest request;
? ?public void setServletRequest(HttpServletRequest request) {
? ?? ???this.request = request;
? ?}
? ?public String execute() throws Exception {
? ?? ???// do the work using the request
? ?? ???return Action.SUCCESS;
? ?}
}
? ?private HttpServletRequest request;
? ?public void setServletRequest(HttpServletRequest request) {
? ?? ???this.request = request;
? ?}
? ?public String execute() throws Exception {
? ?? ???// do the work using the request
? ?? ???return Action.SUCCESS;
? ?}
}
看起來現在這些屬性是類級別的,并不是線程安全的,但是在Struts2里并沒有問題,因為每個請求過來的時候都會產生一個新的action對象實例,它并沒有和其他請求共享一個對象,所以不需要考慮線程安全問題。
現在我們還有最后一步,就是把action關聯上ServletConfigInterceptor 攔截器。這個攔截器繼承了ServletRequestAware 接口,并提供了把HttpServletRequest 注入到action中的功能。但是你現在不用擔心如何配置這些,我們將在下一篇文章中具體講述。最重要的是我們明白了攔截器和接口共同為action提供了反轉控制的功能。
這個設計的好處是能讓action完全和框架解耦。action僅僅是一個被框架使用的簡單的POJO。這對于單元測試但來極大的好處, 你能方便的為Struts action實現 StrutsTestCase 或??MockStrutsTestCase 單元測試。
總結
By到現在為止,你應該已經了解了Struts2的整個請求流程,還有高層的框架概念, 你也應該能自己動手配置Struts2的action,和講出Struts和Struts2的差別了。
在下篇文章中,我們將會介紹一個詳細的Struts應用向Struts2遷移的例子,同時我們也會介紹遷移中相關的知識,會講述如何綜合使用JSTL, JSP 和 Struts2,進一步講述Struts和Struts2的action的差別,Struts2的配置和其他框架元素,和談到更多的其他相關框架的特征。
(自http://www.infoq.com/, cac 翻譯)