作者Ian Roughley譯者陳俊發(fā)布于2007年4月5日 下午8時(shí)0分
大多數人都會(huì )熟悉Struts, 無(wú)論是從項目實(shí)戰中獲得的經(jīng)驗還是從書(shū)中了解到的知識。在這一系列文章里,我們將通過(guò)一個(gè)由Struts遷移到Struts 2的簡(jiǎn)單應用例子向大家展現Struts 2的所有特征。
在我們開(kāi)始介紹這個(gè)例子之前,你需要去了解一點(diǎn)Struts 2的背景知識。文章的第一部分將介紹Struts2與Struts的核心架構的不同點(diǎn),以助于更好地把所有概念聯(lián)系起來(lái)。第二部分將深入探討兩者在actions上的差別、action相關(guān)的框架特征和action的配置。在文章最后一部分將會(huì )講述用戶(hù)界面。我們會(huì )講到其架構、UI構件、主題和標簽,還有如何為我們的應用加上新的外觀(guān)。
我們并不打算談及遷移過(guò)程的所有細節方面,我們只是從普通的出發(fā)點(diǎn)開(kāi)始介紹Struts 2的概念和現在可用的所有新特征。但擁有這些知識后,無(wú)論以后遷移到何等規模的應用到Struts 2中你都可以易如反掌。
Struts的第一個(gè)版本是在2001年5月份發(fā)布的。它的最初設想是通過(guò)結合JSP和Servlet,使Web應用的視圖和業(yè)務(wù)/應用邏輯得以清晰地分離開(kāi)來(lái)。在Struts之前,最常見(jiàn)的做法是在JSP中加入業(yè)務(wù)和應用邏輯,或者在Servlet中通過(guò)println()來(lái)生成視圖。
自從第一版發(fā)布以來(lái),Struts實(shí)際上已成為業(yè)界公認的Web應用標準。它的炙手可熱也為自己帶來(lái)了改進(jìn)和變更,所以不但要跟上對Web應用框架不斷變化的需求,而且要與日漸增多競爭激烈的眾多框架的特性相融合。
到最后,產(chǎn)生了幾個(gè)下一代Struts的解決方案。其中兩個(gè)最受矚目的方案是Shale和StrutsTi。Shale是一個(gè)基于構件的框架,并在最近成為Apache的頂級項目。而StrutsTi則是在Struts的成功經(jīng)驗基礎上繼續堅持對前端控制器(FrontController)和MVC(model-view-controller)模式進(jìn)行改進(jìn)。
WebWork項目是在2002年3月發(fā)布的,它對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真正的繼承者。
最后要注意的是,并不是說(shuō)Struts或WebWork項目已經(jīng)停止開(kāi)發(fā)了。由于人們對這兩個(gè)項目的興趣仍然很高,而且也有很多開(kāi)發(fā)者仍然愿意使用它們,因此這兩個(gè)項目還在繼續開(kāi)發(fā)中,繼續修復Bug,改進(jìn)功能和繼續添加新功能。
在我們開(kāi)始詳細探討如何把應用由Struts遷移到Struts 2之前,讓我們通過(guò)體驗整個(gè)請求流程,看看新架構是如何運作的。
在我們體驗了整個(gè)請求的生命周期后,你應當注意到很重要的一點(diǎn)——Struts 2仍是以前端控制器框架為主體的。所有的概念還都是你以前所熟悉的。
這意味著(zhù):
以下是請求處理過(guò)程的高層概覽:
整個(gè)請求的處理過(guò)程可以分為6步:
你應該已經(jīng)注意到Struts 2和Struts的差別了。最明顯的就是Struts2是一個(gè)pull-MVC架構。這是什么意思呢?從開(kāi)發(fā)者角度看,就是說(shuō)需要顯示給用戶(hù)的數據可以直接從Action中獲取,而不像Struts那樣必須把相應的Bean存到Page、Request或者Session中才能獲取。
首先最重要的是,通過(guò)配置web.xml文件讓框架能在Servlet容器里運行。
下面這個(gè)就是大家都熟悉的Struts在web.xml里的配置方法:
action
org.apache.struts.action.ActionServlet
config
/WEB-INF/struts-config.xml
2
action
*.do
在Struts 2中,配置有少許改變,最明顯的是分發(fā)器(dispatcher)已由Servlet轉為Servlet Filter, 其配置和Servlet一樣簡(jiǎn)單,如下:
webwork
org.apache.struts.action2.dispatcher.FilterDispatcher
webwork
/*
和Servlet配置一樣,Filter配置中定義了Filter的名稱(chēng)(作為引用)和類(lèi)名。FilterMapping通過(guò)URI和名稱(chēng)匹配來(lái)調用相應的Filter。默認情況下,擴展名為“.action”,這是在default.properties文件(在Struts 2 JAR文件里)的“struts.action.extension”屬性定義的。
工具箱:“default.properties”是默認配置選項定義文件。你可以通過(guò)在classpath中包含一個(gè)叫“struts.properties”的文件,設置不同的屬性值,來(lái)覆蓋默認配置的值,實(shí)現自己的配置。
對于Struts來(lái)說(shuō), Servlet配置提供了一個(gè)用于定義文件名的init-param tag來(lái)配置Struts,而Struts 2沒(méi)有這樣的配置參數,取而代之的是在classpath下的默認配置文件“struts.xml”。
工具箱/提示:因為Struts Actions(擴展名“.do”)和Struts 2Actions(擴展名“.action”)兩者的擴展名命名空間不一樣,所以Struts和Struts2可以在同一個(gè)Web應用系統中無(wú)礙地共存。所以這就為遷移提供了很好的條件,加入適當的配置,新功能的開(kāi)發(fā)都用Struts2。保持原有的遺留功能,如果時(shí)間和資源允許的情況下再逐步遷移。另一種方法是,只把Struts2的擴展名改為“.do”,這樣就可使得以前的JSP頁(yè)面可重用。
在上面介紹的請求運作流程中,我們從高層次上談及了一些Struts和Struts 2的不同點(diǎn)?,F在我們將較深入地探討這兩個(gè)框架中Action結構的具體差別。
讓我們來(lái)回顧一下Struts的Action的主要結構。Struts Action的主要形式如下:
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"));
}
}當你實(shí)現一個(gè)Struts Action時(shí), 需要注意以下問(wèn)題:
相比較之下,Struts 2的Action提供了更簡(jiǎn)單的實(shí)現方式。下面就是個(gè)例子:
public class MyAction {
public String execute() throws Exception {
// do the work
return "success";
}
}首先你會(huì )注意到的是,Struts2中的Action不再繼承于任何類(lèi)或需要實(shí)現任何接口。實(shí)際上,它還遠不只這些。按照慣例,只有“execute”方法能調用Action, 但在Struts 2中并非必要,任何聲明為public String methodName() 方法都能通過(guò)配置來(lái)調用Action。
另外,你會(huì )注意到返回的對象不是ActionForward,而是String。如果你不喜歡以字符串的形式出現在你的代碼中,有個(gè)Helper接口A(yíng)ction可以以常量方式提供常見(jiàn)結果,如“success”、“none”、“error”、“input”和“login”。
最后,和Struts最大的革命性的不同是,處理Action過(guò)程中調用的方法(“execute”方法)是不帶參數的。那你如何獲取你所需要的對象呢?答案是使用“反轉控制(Inversion of Control)”,也叫“依賴(lài)注入(DependencyInjection)”的模式(想更多地了解這方面信息請看Martin Fowler的文章http://www.martinfowler.com/articles/injection.html)。Spring框架使得這個(gè)模式流行起來(lái),然而Struts 2的前身(WebWork)也在同時(shí)應用上了這個(gè)模式。
為了更好地了解反轉控制,讓我們來(lái)看看一個(gè)例子,如何在A(yíng)ction處理過(guò)程中可以訪(fǎng)問(wèn)到當前請求HttpServerRequest對象。
在我們的例子中,我們使用的依賴(lài)注入機制是接口注入。就如其名稱(chēng)一樣,接口注入需要的是已經(jīng)被實(shí)現了的接口。這個(gè)接口包含了相應屬性的setter,為Action提供值。例子中我們使用了ServletRequestAware接口,如下:
public interface ServletRequestAware {
public void setServletRequest(HttpServletRequest request);
}當我們繼承這個(gè)接口后,我們原本簡(jiǎn)單的Action看起來(lái)有點(diǎn)復雜了,但是這時(shí)我們可以獲取HttpServerRequest對象來(lái)使用了。
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;
}
}看起來(lái)現在這些屬性是類(lèi)級別的,并不是線(xiàn)程安全的,會(huì )出現問(wèn)題。其實(shí)在Struts 2里并沒(méi)有問(wèn)題,因為每個(gè)請求過(guò)來(lái)的時(shí)候都會(huì )產(chǎn)生一個(gè)新的Action對象實(shí)例,它并沒(méi)有和其他請求共享一個(gè)對象,所以不需要考慮線(xiàn)程安全問(wèn)題。
現在我們還有最后一步,就是為這個(gè)Action關(guān)聯(lián)上ServletConfigInterceptor攔截器。這個(gè)攔截器提供了一系列功能去獲取HttpServletRequest,并可以把它注入到實(shí)現了ServletRequestAware接口A(yíng)ction中。這時(shí)你并不需要擔心如何配置這些,我們將在下一篇文章中有具體講述。最重要的是讓我們明白到是攔截器和接口共同合作下為Action提供了反轉控制功能的。
這個(gè)設計的好處是能讓Action和框架完全解耦。Action僅僅是一個(gè)與框架無(wú)關(guān)的簡(jiǎn)單POJO。這給單元測試帶來(lái)極大的好處,Struts2 Action的單元測試遠比Struts Action使用StrutsTestCase或MockStrutsTestCase的單元測試簡(jiǎn)單。
到現在為止,你應該對Struts2的基礎有所了解了——包括高層的框架概念和基礎的請求流程。你也應該能自己動(dòng)手在Servlet容器里配置Struts 2,并理解Struts和Struts 2兩者之間在A(yíng)ction方面的差別了。
在下篇文章中,我們將會(huì )介紹一個(gè)詳細的遷移的例子,同時(shí)我們也在這章學(xué)到的知識基礎上,演示如何由Struts向Struts2的Action遷移。在最后講述如何在應用中使用JSTL、JSP和Struts2。我們會(huì )進(jìn)一步探討Struts和Struts2在A(yíng)ction上的區別,Struts 2的配置和其他框架元素,和談到更多的Action相關(guān)的框架特征。
Ian Roughley是一位技術(shù)演講人、作家及獨立咨詢(xún)顧問(wèn),住在馬薩諸塞州的波士頓。他具有十多年提供架構設計、開(kāi)發(fā)、過(guò)程改進(jìn)以及指導等方面服務(wù)的經(jīng)驗,客戶(hù)范圍小至創(chuàng )業(yè)公司,大到財富500強前10名的公司。他專(zhuān)注于具有實(shí)效性且以結果為目標的方法,是開(kāi)源及以敏捷開(kāi)發(fā)為基礎的過(guò)程和質(zhì)量改進(jìn)的支持者。
陳俊是SpringSide開(kāi)源項目的主力成員,中科院軟件工程碩士,就職于A(yíng)ccenture。長(cháng)期從事J2EE企業(yè)級應用開(kāi)發(fā),略有小成。熱衷于軟件體系結構,設計模式,軟件過(guò)程改進(jìn)及敏捷開(kāi)發(fā)研究,以成為出色的架構師為目標。愛(ài)嘗試不同的開(kāi)源技術(shù),一直投身SpringSide開(kāi)發(fā),為國內開(kāi)源出一分綿力。
聯(lián)系客服