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

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

整個(gè)請(qǐng)求過(guò)程可以分為六步驟:
- 一個(gè)請(qǐng)求產(chǎn)生并經(jīng)由框架處理 - 框架根據(jù)請(qǐng)求匹配相應(yīng)的配置,如使用哪些攔截器,action 類(lèi)和結(jié)果。
- 請(qǐng)求通過(guò)一系列的攔截器 - 攔截器,和攔截器組經(jīng)配置后,能處理不同等級(jí)的請(qǐng)求,它們?yōu)檎?qǐng)求提供了各種預(yù)處理,切面處理。這和Struts的使用 Jakarta Commons Chain 構(gòu)件的 RequestProcessor類(lèi)很相似。
- 調(diào)用 Action - 產(chǎn)生一個(gè)新的action對(duì)象實(shí)例,并提供請(qǐng)求所調(diào)用的處理邏輯的方法。Struts2 可以在配置action時(shí)為請(qǐng)求分配其指定的方法。我們?cè)诘诙课恼轮袑?duì)這步驟進(jìn)行進(jìn)一步討論;
- 調(diào)用產(chǎn)生的結(jié)果 - 獲取通過(guò)action的方法處理后返回來(lái)的結(jié)果,匹配其result class并調(diào)用產(chǎn)生的實(shí)例。有種情況是在UI模板去生成HTML時(shí)才去處理這些結(jié)果。如果在這種情況下,在Struts2 模板中的tags能直接返回到 action 中,取結(jié)果來(lái)呈現(xiàn)界面。
- 請(qǐng)求再次經(jīng)過(guò)一系列的攔截器處理后返回 - 請(qǐng)求反順序通過(guò)與原來(lái)進(jìn)入時(shí)的攔截器鏈, 當(dāng)然,你也可以配置在這個(gè)過(guò)程中減少或增加攔截器處理.
- 請(qǐng)求返回到用戶(hù) - 最后一步是由 control 返回到servlet。通常是生成HTML返回到user, 但你也可以指定返回的HTTP頭或HTTP重定向。
配置框架
首先最重要的是,讓框架能通過(guò)web.xml在servlet containers里運(yùn)行。
下面這個(gè)就是大家都熟悉的 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 中,這個(gè)有少許改變,最明顯的是dispatcher 由servlet轉(zhuǎn)為servlet filter, 其配置和servlet一樣簡(jiǎn)單,如下:
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配置定義了名稱(chēng)(供關(guān)聯(lián))和filter的類(lèi)。filter mapping讓URI匹配成功的的請(qǐng)求調(diào)用該filter。默認(rèn)情況下,擴(kuò)展名為".action"。
這個(gè)是在default.properties文件里的"struts.action.extension" 屬性定義的。
工具箱:??"default.properties"是配置選項(xiàng)定義文件。通過(guò)在classpath中包含一個(gè)叫"struts.properties"的文件,并設(shè)置不同的屬性值,你可以覆蓋這個(gè)默認(rèn)的配置,實(shí)現(xiàn)自己的配置。對(duì)于Struts, servlet配置提供了初始化tag的參數(shù)和使用的文件,而Struts2沒(méi)有這樣的配置參數(shù),取而代之的是在classpath下的默認(rèn)配置文件"struts.xml"。
工具箱/提示: Struts actions(擴(kuò)展名".do"),Struts2 actions(擴(kuò)展名".action"),所以Struts和Struts2可以在一個(gè)系統(tǒng)中共存。所以最好是保持原先的系統(tǒng),在新功能的開(kāi)發(fā)上用Struts2, 如果時(shí)間和資源允許的情況下再逐步遷移。另一種方法是只是把Struts2的擴(kuò)展名改為".do",可重用JSPs.分析Actions
在上面介紹的請(qǐng)求運(yùn)作流程中,我們談及了一些Struts和Struts2的不同點(diǎn)。現(xiàn)在我們將較深入地探討這兩個(gè)框架中action結(jié)構(gòu)的具體差別。
讓我們來(lái)回顧一下 Struts 的 action 結(jié)構(gòu), 主要的形式如下:
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"));
? ? }
}
當(dāng)實(shí)現(xiàn)一個(gè)Struts action時(shí), 你需要注意一下問(wèn)題:
- 所有的action 都必須繼承于base Action 類(lèi).
- 所有的action都必須是線(xiàn)程安全的,因?yàn)閍ction是單例的,singleton的.
- 因?yàn)樗械腶ction都必須是線(xiàn)程安全的,所以所有的對(duì)象都不能是類(lèi)屬性, 都必須以方法參數(shù)的形式傳值。
- 調(diào)用action的方法必須命名為 "execute" ( 在Struts中的??DispatchAction 類(lèi)好像可以用其它方法去執(zhí)行同一個(gè)action ,但實(shí)際上在框架中調(diào)用的仍然是 "execute" 方法。).
- ActionForward 的結(jié)果是通過(guò)ActionMapping 類(lèi)中的方法來(lái)產(chǎn)生的,通常是"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";
? ?}
}
首先你會(huì)注意到的是,Struts2中的action不再繼承于任何類(lèi)或需要實(shí)現(xiàn)任何接口。實(shí)際上,它還遠(yuǎn)不只這些。按照慣例,只有"execute"方法能調(diào)用action, 但在Struts2中并非必要,任何聲明為public String methodName() 方法都能通過(guò)配置來(lái)調(diào)用action.
另外,你會(huì)注意到返回值不再是"ActionForward ",而是String, 如果你需喜歡String的形式,那在Action接口里有個(gè)幫助方法可以提供簡(jiǎn)單的結(jié)果常量,如"success", "none", "error", "input" 和 "login"。
最后,和Struts最大的革命性的不同是, 調(diào)用action不再是帶參數(shù)的。那你如何在獲得你所需要的值呢?答案是"inversion of control" 或 "dependency injection", 反轉(zhuǎn)控制(想了解更多可以看Martin Fowler的文章 http://www.martinfowler.com/articles/injection.html)。
為了更好地了解反轉(zhuǎn)控制,讓我們來(lái)看看一個(gè)例子,如何在action處理過(guò)程中可以訪(fǎng)問(wèn)到HttpServerRequest 。在我們的例子中,我們用ServletRequestAware 接口,這個(gè)接口包含了相應(yīng)屬性的setter,如下
CODE:
public interface ServletRequestAware {
? ? public void setServletRequest(HttpServletRequest request);
}
? ? public void setServletRequest(HttpServletRequest request);
}
當(dāng)我們繼承這個(gè)接口時(shí),我們需要通過(guò)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;
? ?}
}
看起來(lái)現(xiàn)在這些屬性是類(lèi)級(jí)別的,并不是線(xiàn)程安全的,但是在Struts2里并沒(méi)有問(wèn)題,因?yàn)槊總€(gè)請(qǐng)求過(guò)來(lái)的時(shí)候都會(huì)產(chǎn)生一個(gè)新的action對(duì)象實(shí)例,它并沒(méi)有和其他請(qǐng)求共享一個(gè)對(duì)象,所以不需要考慮線(xiàn)程安全問(wèn)題。
現(xiàn)在我們還有最后一步,就是把a(bǔ)ction關(guān)聯(lián)上ServletConfigInterceptor 攔截器。這個(gè)攔截器繼承了ServletRequestAware 接口,并提供了把HttpServletRequest 注入到action中的功能。但是你現(xiàn)在不用擔(dān)心如何配置這些,我們將在下一篇文章中具體講述。最重要的是我們明白了攔截器和接口共同為action提供了反轉(zhuǎn)控制的功能。
這個(gè)設(shè)計(jì)的好處是能讓action完全和框架解耦。action僅僅是一個(gè)被框架使用的簡(jiǎn)單的POJO。這對(duì)于單元測(cè)試但來(lái)極大的好處, 你能方便的為Struts action實(shí)現(xiàn) StrutsTestCase 或??MockStrutsTestCase 單元測(cè)試。
總結(jié)
By到現(xiàn)在為止,你應(yīng)該已經(jīng)了解了Struts2的整個(gè)請(qǐng)求流程,還有高層的框架概念, 你也應(yīng)該能自己動(dòng)手配置Struts2的action,和講出Struts和Struts2的差別了。
在下篇文章中,我們將會(huì)介紹一個(gè)詳細(xì)的Struts應(yīng)用向Struts2遷移的例子,同時(shí)我們也會(huì)介紹遷移中相關(guān)的知識(shí),會(huì)講述如何綜合使用JSTL, JSP 和 Struts2,進(jìn)一步講述Struts和Struts2的action的差別,Struts2的配置和其他框架元素,和談到更多的其他相關(guān)框架的特征。
(自http://www.infoq.com/, cac 翻譯)