(转自http://www.blogjava.net/moxie/archive/2006/10/20/76375.html)WebWork深入浅出
(轉自http://www.blogjava.net/moxie/archive/2006/10/20/76375.html)
WebWork深入淺出
本文發表于《開源大本營》???????????
?????????????????????作者:錢安川
前言
本篇文章并沒有太多WebWork?的實戰代碼細節。本人非常希望能充當一名導游的角色,帶領讀者逐步游覽WebWork的功能特性和原理。在第一章,我們將提出基于三層架構的Web層需要解決的10個問題,這是本文的縱軸。圍繞著縱軸,我們按照橫軸的順序逐步描述講解:WebWork簡介、WebWork入門、WebWork原理、WebWork實戰和技巧、展望WebWork未來、最后是本文的總結。
基于三層架構的?Web?層需要解決的問題
我們這里討論的Web層,是基于典型的三層架構:Web層,業務層,數據層。故,我們將不討論任何涉及業務(業務邏輯)層和數據層功能的實現。
Web層需要解決的問題:
1、??數據的輸入。如何獲得基于無狀態HTTP的請求數據?如何將請求的字符數據轉換為對應的模型對象?
2、??輸入數據的驗證。如何驗證輸入數據的合法性并給出明確的錯誤消息提示??
3、??數據的輸出。如何展現復雜的對象結構?如何處理復雜的展現邏輯?
4、??數據的傳遞和共享。如何在不同的請求或頁面之間傳遞和共享數據?
5、??頁面的流程管理。如何管理Web應用中的頁面流程?
6、??模塊化的管理。如何將復雜的Web應用以模塊化的方式管理?
7、??靈活可擴展的架構。如何支持各種不同的展現層技術?如何與業務層或數據層的各種框架整合?
8、??安全和訪問控制的管理。如何提供基于Web的安全機制和資源訪問控制的管理?
9、??代碼實現的簡潔和高效。如何讓開發步驟和代碼維護變得簡單?如何盡量減少開發的中間環節?如何將公共的功能剝離出來,并可以靈活的組裝應用?
10、??????????????????????其它問題。異步調用、國際化支持、文件上傳、防止重復提交等等。
下面,讓我們來一起看看WebWork是如何解決上面的這些問題。
?
WebWork?簡介
?
WebWork是由OpenSymphony組織開發的,致力于組件化和代碼重用的J2EE Web框架。WebWork目前最新版本是2.2.2,現在的WebWork2.x前身是Rickard Oberg開發的WebWork,但現在WebWork已經被拆分成了Xwork1和WebWork2兩個項目,如下示意圖所示:
| ? |
?
?work簡潔、靈活功能強大,它是一個標準的Command模式框架實現,并且完全從web層脫離出來。Xwork提供了很多核心功能:前端攔截機(interceptor),運行時表單屬性驗證,類型轉換,強大的表達式語言(OGNL – the Object Graph Notation Language),IoC(Inversion of Control依賴倒轉控制)容器等。
WebWork2建立在Xwork之上,處理HTTP的請求和響應。所有的請求都會被它的前端控制器(ServletDispatcher,最新版本是FilterDispatcher)截獲。前端控制器對請求的數據進行包裝,初始化上下文數據,根據配置文件查找請求URL對應的Action類,執行Action,將執行結果轉發到相應的展現頁面。WebWork2支持多視圖表示,視圖部分可以使用JSP, Velocity, FreeMarker, JasperReports,XML等。
下面我們提到的WebWork將為WebWork2,使用的版本是WebWork2.2.2。
?
WebWork?入門
WebWork?安裝
如果只是搭建一個WebWork開發環境,那將非常簡單:
1、??去網站http://www.opensymphony.com/webwork下載最新的WebWork2.2.2項目。
2、??搭建一個Web應用(這個不難吧);并拷貝WebWork框架運行需要的所有Jar文件到Web應用的WEB-INF\lib中。這些Jar文件,可以在WebWork項目中lib\default目錄找到,即那個目錄里面的所有文件。當然,別忘記今天的“主角”,在WebWork跟目錄下的webwork-2.2.2.jar文件。
3、??在Web.xml文件中配置WebWork的前端控制器FilterDispatcher,也就是一個普通的Servlet Filter(過濾器)而已。代碼如下:
????<?filter?>
????????<?filter-name?>?webwork?</?filter-name?>
????????<?filter-class?>?com.opensymphony.webwork.dispatcher.FilterDispatcher?</?filter-class?>
????</?filter?>
?
????<?filter-mapping?>
????????<?filter-name?>?webwork?</?filter-name?>
????????<?url-pattern?>?/*?</?url-pattern?>
??</?filter-mapping?>
?
不過如果是在實際項目中使用,安裝過程中還是有一些問題需要注意的:
1、??關于前端控制器。在以前WebWork2版本里面,前端控制器是ServeltDispatcher,它是一個JavaServlet。而現在是一個Filter(過濾器),會導致無法在頁面中使用Jsp的include來包含一個WebWork的Action請求的URL。如果真的需要這樣做,可以使用WebWork的action標簽庫。
2、??關于Action請求URL的后綴。我們知道,在一般的Web框架中,前端控制器會將特定后綴的請求URL映射到對應的Action請求中。而我們這里的前端控制器會接受任意的請求,但它默認是將.action結尾的URL映射為WebWork的Action請求。我們可以在webwork.properties文件中,設置我們自己的后綴名,多個后綴名可以用逗號隔開。例如:webwork.action.extension=action,do
3、??在?Jsp?頁面中,?WebWork?的標簽庫不需要在?web.xml?中定義,在頁面中通過如下的代碼直接引用:?<%@?taglib?prefix?=?"ww"?uri?=?"/webwork"?%>
4、??在Jsp頁面中,默認“altSyntax”是開啟的。它是用來解決標簽庫中的字符串和表達式語言混淆的問題。所以,作為變量的表達式語言應該放在%{}中,否則WebWork會把它當作字符串處理。
5、??如果展現層技術使用Freemarker(WebWork官方的推薦,也是我個人的推薦),如果在頁面中需要使用標簽庫,必須在web.xml中配置JspSupportServlet,代碼如下:
??????<?servlet?>
??????<?servlet-name?>?JspSupportServlet?</?servlet-name?>
??????<?servlet-class?>?com.opensymphony.webwork.views.JspSupportServlet?</?servlet-class?>
??????<?load-on-startup?>?1?</?load-on-startup?>
???</?servlet?>
6、??還有一些其它的定制,比如:編碼,標簽的模板文件等等,都可以在webwork.properties文件中配置。如果在ClassPath中沒有這個文件,WebWork會自動讀取WebWork的Jar包里面的default.properties文件。
WebWork?核心概念
WebWork的三個關鍵部分
1、??Actions。一般一個Action代表一次請求或調用。在WebWork中,一般Action類需要實現Action接口,或者直接繼承基礎類ActionSupport。這是,它要實現默認的execute方法,并返回一個在配置文件中定義的Result(也就是一個自定義的字符串而已)。當然,Action也可以只是一個POJO(普通Java對象),不用繼承任何類也不用實現任何接口。Action是一次請求的控制器,同時也充當數據模型的角色,我們強烈建議不要將業務邏輯放在Action中。
2、??Results。它是一個結果頁面的定義。它用來指示Action執行之后,如何顯示執行的結果。Result Type表示如何以及用哪種視圖技術展現結果。通過Result Type,WebWork可以方便的支持多種視圖技術;而且這些視圖技術可以互相切換,Action部分不需做任何改動。
3、??Interceptors。WebWork的攔截器,WebWork截獲Action請求,在Action執行之前或之后調用攔截器方法。這樣,可以用插拔的方式將功能注入到Action中。WebWork框架的很多功能都是以攔截器的形式提供出來。例如:參數組裝,驗證,國際化,文件上傳等等。
第一個例子:?Welcome
?
入門,我們從簡單的Welcome開始吧!需求如下:一個頁面,有一個用戶名輸入框;輸入自己的名字,例如Moxie,提交按鈕返回一個歡迎的頁面,并顯示前面輸入的用戶名和一句歡迎信息,例如:Moxie, Welcome!頁面操作流程圖如下:
?
?
| WelcomeAcion.java |
| welcomeResult.jsp |
| welcome.jsp |
開發步驟如下:
1、??輸入頁面。Welcome.jsp是一個非常簡單輸入頁面,代碼如下:
?
<?form?name?=?"register"?action?=?"welcome.action"?method?=?"POST"?>
??????Name:?<?input?name?=?"username"?>?Please input your name.
</?form?>
2、??WebWork的Action類。它實現了Action接口,獲得welcome.jsp頁面傳入的數據即輸入的用戶名,根據這個用戶名生成了一條歡迎信息,并在結果頁面中打印出來。WelcomeAction.java代碼如下:
?
public class WelcomeAction implements Action{
??????private String username;
??????private String welcomeMessage;
?
??????public String execute() throws Exception {
????????????welcomeMessage = username +",Welcome!";
????????????return SUCCESS;
??????}
?????
??????public void setUsername(String username) {
????????????this.username = username;
??????}
?????
??????public String getWelcomeMessage() {
????????????return welcomeMessage;
??????}
}
看了上面的代碼,也許你都不敢相信這就是?Web?編程。沒有調用任何一個?JavaServlet?的?API?,它是如何獲得請求的數據并將執行結果暴露給輸入頁面的呢?它是通過值堆棧和表達式語言來實現(后面會有詳細介紹)。我們先看看?Action?是如何獲得請求的數據。輸入框的名字“?username?”,即請求的參數的名字,它就是一個表達式語言。WebWork?遇到這個表達式語言,就會執行相應的?setUsername?方法,而?username?參數的值就是執行這個方法的參數。這些是在?Action?執行?execute?方法之前完成,這樣?Action?就可以獲得請求的數據對象。類似的原理,?WebWork?也是通過表達式語言將?getWelcomeMessage?方法暴露給結果頁面。
3、??結果頁面。welcomeResult.jsp頁面,將通過表達式語言,取得Action執行之后暴露出來的數據對象。代碼如下:
<%@?taglib?prefix?=?"ww"?uri?=?"/webwork"?%>
<?ww:property?value?=?"%{welcomeMessage}"?/>
我們在結果頁面中使用了?WebWork?標簽庫。我們用到的是?property?標簽,它通過表達式語言,打印?Action?暴露出的數據對象。
4、??定義配置文件xwork.xml。代碼如下:
<?xwork?>
????<?include?file?=?"webwork-default.xml"?/>
????<?package?name?=?"default"?extends?=?"webwork-default"?>
??<?action?name?=?"welcome"?class?=?"com.noname.web.action.WelcomeAction"?>
????????????<?result?name?=?"success"?type?=?"dispatcher"?>?/welcomeResult.jsp?</?result?>
??????????????<?interceptor-ref?name?=?"params"?/>
??????</?action?>
</package>
</xwork>
“?name?”參數用于請求的?URL?。例如:?http://localhost/welcome.action?,這樣通過請求的?url?,我們就可以在配置文件中找到對應的?action?。“?class?”即實現Action?的類。一個?Action?中可以定義多個?Result?。?Result?的“?name?”對應?Action?方法返回的字符串。在我們的?WelcomeAction?方法中,執行成功之后返回字符串“?success?”。即我們在這個?Action?里定義的那個?result?。“?interceptor-ref?”定義這個?action?所使用到的攔截器。我們這里使用了?WebWork?提供的params?攔截器,它能自動的幫我們將請求的參數組裝成?Action?中需要的數據對象。通過這個攔截器,它會調用?Action?的?setUsername?方法,取得?username?參數的值,這樣?Action?就可以獲得用戶輸入的?username?數據。也許你會奇怪,?params?這個攔截器是從哪里變出來的?這個?xwork.xml?文件包含了?WebWork?提供的默認配置文件?webwork-default.xml,可以在webwork-2.2.2.jar文件中找到。我們定義的這個package繼承了它里面的package“webwork-default”,這樣就可以共享“webwork-default”package里面定義的所有攔截器。
?
?
WebWork?原理
通過上面的例子,我們已經了解WebWork開發、運行的基本流程(一定要親自安裝,并開發這個Welcome的例子哦)。如果要在實際項目中使用WebWork,我們必須要了解下面的概念和WebWork的原理。
?
ValueStack(?值堆棧?)?和?EL(?表達式語言?)
關于ValueStack的描述:
1、??ValueStack其實就是一個放置Java對象的堆棧而已,唯一特別的是可以使用EL來獲得值堆棧中對象屬性的數據,并可以為值堆棧的對象屬性賦值。
2、??EL,全稱Express Language,即表達式語言。不要被語言嚇倒,它是簡單的對象導航語言。有字符串(例如:方法名)和特殊字符組成(例如用.表示調用對應的屬性方法)。通過EL,我們可以存、取對象數據,而且還可以直接訪問類的靜態數據,調用靜態方法。
3、??WebWork的ValueStack底層有第三方開源項目OGNL實現。所以EL也都遵循OGNL的規范。我們在開發中,幾乎不需要知道OGNL的細節。
4、??WebWork為每一次請求構建一個ValueStack,并將所有相關的數據對象(例如:Action對象、Model對象等)放到ValueStack中。再將ValueStack暴露給視圖頁面,這樣頁面就可以直接訪問后臺處理生成的數據。
下面我們用一個雇員類為例,使用Junit框架(單元測試框架)來展示ValueStack的功能。
我們有一個Employee類,它有兩個屬性:姓名,地址。姓名是一個字符串,地址是一個對象,地址類有國家、城市、街道三個屬性。代碼如下:
Employee.java代碼如下:
public class Employee {
??????private String name;
?????
??????private Address address;
?????
??????public Employee() {
??????}
?????
??????public String getName() {
????????????return name;
??????}
?
??????public void setName(String name) {
????????????this.name = name;
??????}
?
??????public Address getAddress() {
????????????if(address == null)
??????????????????address = new Address();
????????????return address;
??????}
?????
??????public void setAddress(Address address) {
????????????this.address = address;
??????}
}
?
Address.java代碼如下:
public class Address {
????????????private String country;
????????????private String city;
????????????private?String street;
???????????
????????????……
????????????//默認的Get和Set方法,省略
???????????
}
下面出場的是OgnlValueStackTest,它有兩個測試方法。分別測試使用EL從ValueStack中取值和存值。代碼如下:
import com.opensymphony.xwork.util.OgnlValueStack;
import junit.framework.TestCase;
?
public class OgnlValueStackTest extends TestCase {
????????????private OgnlValueStack valueStack;
????????????private Employee employee;
???????????
????????????@Override
????????????protected void setUp() throws Exception {
????????????????????????valueStack = new OgnlValueStack();
????????????????????????employee = new Employee();
????????????????????????valueStack.push(employee);
????????????}
?
????????????public void testCouldGetDataFromObjectInOgnlValueStackByEL() throws Exception{
????????????????????????employee.setName("Moxie");
????????????????????????Address address = new Address();
????????????????????????address.setCountry("China");
????????????????????????employee.setAddress(address);
???????????????????????
????????????????????????assertEquals("Moxie",valueStack.findValue("name"));
????????????????????????assertEquals("China",valueStack.findValue("address.country"));
????????????}
???????????
????????????public void testCouldSetDataForObjectInOgnlValueStackByEL() throws Exception{
????????????????????????valueStack.setValue("name","Moxie");
????????????????????????valueStack.setValue("address.country","China");
???????????????????????
????????????????????????assertEquals("Moxie",employee.getName());
????????????????????????assertEquals("China",employee.getAddress().getCountry());
????????????}
}
這是一個Junit Test,關于Junit的使用不是本篇文章的范疇。作為一個Java開發者,熟悉這樣的測試框架是最基本的要求。setUp方法在每個測試方法調用之前都會執行,它用來初始化每個測試方法都需要的對象和數據。我們的setUp方法首先創建兩個對象:valueStack對象和employee對象,然后將employee對象入棧。這樣,emloyee對象就在值堆棧的最上端。
第一個測試方法testCouldGetDataFromObjectInOgnlValueStackByEL測試可以用表達式語言取得值堆棧里的對象數據。我們首先為值堆棧里的employee對象設置數據,設置了用戶名和用戶地址所在的國家。
第一個驗證斷言?????????????assertEquals("Moxie",valueStack.findValue("name"))解釋為:我們期望使用表達式語言“name”去ValueStack中查找得到的對象是”Moxie”。即期望valueStack.findValue("name")語句執行返回的數據是”Moxie”對象。再深入下去,這條語句會調用ValueStack里對象的getName方法(即employee對象的getName方法),并返回這個方法返回的數據。
第二個斷言assertEquals("China",valueStack.findValue("address.country"))。它期望表達式語言“address.country”取得的數據是對象的address屬性對象的country屬性,即取得雇員對象的地址所在的國家。深入下去,它也就是調用對象employee的getAddress().getCountry()方法。??第二個測試方法testCouldSetDataForObjectInOgnlValueStackByEL測試通過表達式語言為ValueStack中的對象設置數據。
第一個設值語句valueStack.setValue("name","Moxie"),它通過表達式語言“name”將“”Moxie””賦值給ValueStack里的對象,即調用值堆棧中的對象的setName方法,并把后面的值作為方法的參數。同理,第二個設置語句會調用值堆棧中的對象的getAddress().setCountry()方法,把后面的數據作為setCountry方法的參數。
?
看了這個例子,我們就會知道如何通過ValueStack進行數據的存取。在我們使用ValueStack時需要注意:
1、??所有存取操作的目標對象都是已放入ValueStack中的對象。所以在使用之前,必須要先將對象入棧。例如我們在setup方法中的語句:valueStack.push(employee)。
2、??每一次WebWork請求,在創建Action對象之前都會先生成一個ValueStack對象,再將Action對象入棧。這樣我們就可以通過表達式語言來直接存取action對象的數據,所以在WebWork中,action具有數據模型的功能。
3、??在對ValueStack進行存取操作時,我們的操作指令(表達式語言)并不知道它是對哪個對象進行操作。例如,我們在獲取員工姓名時,我們給的操作指令是”name”,這時,并不知道ValueStack里面的對象一定就是employee。ValueStack會從上而下,遍歷棧里面的對象,并試圖調用當前遍歷對象的getName方法,當它找到了這個方法,并執行之后,就會將執行得到的數據返回。這就是那神秘的ValueStack。
4、??關于值堆棧的context map,它是一個放置值堆棧上下文數據的對象。通過符號“#“再加上對象的名稱,可以訪問這些數據(只可以訪問)。一些JavaServlet相關的數據都放在這個容器中。這個對webwork的標簽庫特別有用,這樣我們可以直接通過表達式語言去訪問request、attribute、session、application里的數據。例如:用property標簽庫打印出所有請求參數的數據,代碼如下:<ww:property value="%{#request}"/>。
5、??其它。“top”是ValueStack里面的關鍵字,通過它可以找到ValueStack中最上面的那個對象。可以試著打印一下valueStack.findValue("top"))看看。表達式語言除了可以調用基于JavaBean規范的get和set方法之外,還可以調用一般的Java方法(這是需要使用方法的全名,并傳入需要的參數),也可以直接訪問Java類的靜態字段和靜態方法。具體的使用,可以查看WebWork的官方文檔。
?
Interceptor(?攔截器?)
攔截器在前面的“WebWork核心概念”章節做了簡單介紹,這里我們將對它進行更進一步的探討。關于攔截器的描述:
1、??一個攔截器就是在xwork.xml文件中定義的一個無狀態Java類,它至少要實現XWork的com.opensymphony.xwork.interceptor.Interceptor接口。代碼如下:
public interface Interceptor extends Serializable {
????void destroy();
?
????void init();
?
????String intercept(ActionInvocation invocation) throws Exception;
}
2、??實現Interceptor接口的攔截器,代碼部分在intercept方法中實現。在intercept方法中,可以直接返回一個Result字符串,這樣整個執行直接“短路”,這時Action的execute方法也不會執行(一般很少會這么用)。所以,一般都會在這個方法里調用參數對象invocation的invoke方法,并返回這個方法執行的結果。這樣會持續執行后面的攔截器方法以及Action的execute方法等。
3、??大部分的時候,攔截器直接繼承WebWork的抽象類com.opensymphony.xwork.interceptor.AroundInterceptor就可以了。這時,需要實現它的before和after方法。Before方法會在Action執行之前調用,after方法在Action執行之后調用。
4、??攔截器的執行順序。我們可將多個攔截器放一起組裝成一個攔截器棧。這樣攔截器會按照棧的順序由上而下執行before方法,所有before方法執行結束,再執行Action的方法,執行Result的方法,再返回執行結果,最后再從下而上執行攔截器的after方法。
5、??攔截器的過濾功能。我們通常會在應用中使用一個通用的定義多個攔截器的攔截器棧。但有些Action方法在調用的時候,不需要要其中的部分攔截器。這時,我們就可以使用攔截器過濾功能。如果攔截器要擁有過濾功能,必須實現抽象類com.opensymphony.xwork.interceptor.MethodFilterInterceptor。這樣,攔截器在定義的時候或者在Action引用攔截器棧的時候,我們就可以指定哪些Action方法是需要過濾的,哪些Action是不需要過濾的。
?
WebWork提供的攔截器介紹
1、??自動為Action設置Http請求數據的攔截器(Parameters Interceptor)。這個攔截器非常方便實用,但完全自動組裝對象數據,很可能會帶來安全問題。如果Action不需要設置數據,那么這個Action只要實現com.opensymphony.xwork.interceptor.NoParameters接口即可。如果是Action中部分數據需要自動設置,部分數據不允許設置,這樣可以實現接口com.opensymphony.xwork.interceptor.ParameterNameAware,可以在這個接口的acceptableParameterName(String parameterName)方法中,定義我們可以接受哪些方法,如果允許只要讓這個方法返回True就可以了。
2、??過慮參數功能的攔截器(Parameter Filter Interceptor)。它可以全局阻止非法或不允許Action訪問的參數。可以很好的和上面的組裝參數的攔截器一起使用。
3、??為Action設置靜態數據的攔截器(Static Parameters Interceptor)。它可以將Action定義的靜態<param/>參數,設置到Action中。
4、??數據驗證攔截器(Validation Interceptor)。定義之后,會調用驗證文件或實現驗證接口com.opensymphony.xwork.Validateable的所有驗證。
5、??驗證流程處理攔截器(Workflow Interceptor)。它和上面的攔截器一起使用,處理驗證的流程。如果驗證通過則繼續前進,如果發現有驗證錯誤消息,直接轉到Action中定義的輸入結果(input)頁面。
6、??類型轉換錯誤處理攔截器()。它首先去取得類型轉換的錯誤消息(主要是由設置Http請求參數的攔截器產生),如果取到錯誤消息,它會將錯誤消息傳遞給實現接口com.opensymphony.xwork.ValidationAware的Action,這樣我們可以將這些錯誤消息暴露到頁面中。
7、??Action鏈攔截器(Chaining Interceptor)。它是用來拷貝前一個Action的屬性數據到當前Action中。它要求前一個Action必須是chain Result(<result type="chain">),這樣才能進行Action的數據拷貝。
8、??防止頁面重復提交(或頁面重復刷新)攔截器。Token Interceptor和Token Session Interceptor都是防止重復提交的攔截器。不同點是后者在Session存貯了最近一次請求的結果數據。
9、??文件上傳的攔截器(File Upload Interceptor)。實現文件上傳的功能。如果有人曾經手工寫過文件上傳程序,那一定會驚嘆于這個攔截器。我們可以在這個攔截器中設定上傳文件的大小和類型限制。記得需要第三方的文件上傳庫的支持,只要在webwork.properties中配置過,并拷貝相應的jar包就可以了。
10、??????????????????????進度條等待攔截器(Execute and Wait Interceptor)。當Action的執行需要很長實際的時候,我們可以使用這個進度條等待的攔截器。它會將Action放到后臺執行,而在前端顯示進度條或等待消息提示的頁面。
11、??????????????????????還有一些其它不常用的攔截器,我們可以在WebWork文檔中找到,這里就不再做介紹。
IoC?容器
關于IoC容器的描述:
1、??它是一個容器。用來處理不同對象之間的依賴,組裝不同的程序元素。
2、??IoC全名是Inversion of Control,即依賴反轉控制。它是一種設計模式,IoC容器就是基于這個模式的實現。
3、??有一個比IoC更適合用來命名這一原理的名詞,它叫Dependency Injection,即依賴注入。
4、??有了依賴注入,我們可以將IoC容器簡單理解為:它是一個用來為對象組裝其依賴的對象的容器;也就是說對象本身不用關心它依賴的對象(可以是組件或者服務,反正就是提供業務方法的對象)的創建,初始化,生命周期等,而是由容器來控制。
5、??關于IoC的更多信息可以查看Martin Fowler的經典文章《IoC?容器和Dependency Injection?模式》
WebWork框架本身就提供了一個基于接口的IoC容器。同時WebWork框架和提供了和第三方IoC容器的集成。在WebWork的項目中,我們可以直接使用Spring框架和Pico框架作為自己的IoC容器。而且Spring是WebWork官方推薦的IoC容器。
下面我們將介紹如何使用Spring作為WebWork的IoC容器。在討論如何集成Spring之前,我們要討論一個非常有意義的架構問題:
WebWork的Action類是否需要由Spring管理?
1、??否。這樣Action類還是象以前那樣在xwork文件中定義,我們可以通過標簽<external-ref/>定義Action所依賴的Bean組件,或者根據Bean的名字或類型進行自動注入。
2、??是。Action類本身也是有Spring來管理。在xwork定義文件中的Action class就是對Bean的引用,具體的類在Spring的Bean配置文件中定義。這樣可以更好的使用Sping為我們提供的更多功能,例如:Spring的復雜AOP功能,基于Acegi的權限控制,等等。
兩種方法,根據需要選擇一種,我個人更傾向后者。下面我們介紹一下Spring容器的安裝步驟:
1、??拷貝Spring依賴的所有jar文件
2、??在web.xml文件定義和開啟Spring的監聽器,代碼如下:
<listener>
??????<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
??????</listener>
3、??在webwork.properties中設置WebWork對Spring的支持:webwork.objectFactory = spring
4、??可以在webwork.properties中設置Bean組件的默認組裝方式,默認是按照Bean的名稱,可以選擇按照類型、構造函數、自動選擇等方式。
?
WebWork?原理
?
WebWork的網站上提供了一個完整的WebWork架構圖。它描述了從客戶端的一次請求到最后服務器端響應的的整個執行過程。架構圖如下:
?
此架構圖一個分為五個部分,其中五個部分分別有五中不同顏色表示。
1、??淺灰色方框。分別代表了客戶端的一次Http請求,和服務器端運算結束之后的一次響應。
2、??淺紅色方框。表示一次Action請求所要經過的Servlet filters(Servlet?過濾器)。我們可以看到最后一個filter就是我們前面介紹的WebWork的前端控制器。
3、??藍色方框。這是WebWork框架的核心部分。
1)??一次請求到了WebWork的前端控制器,它首先會根據請求的URL解析出對應的action?名稱,然后去咨詢ActionMapper這個action是否需要被執行。
2)??如果ActionMapper決定這個action需要被執行,前端控制器就把工作委派給ActionProxy。接著她們會咨詢WebWork的配置管理器,并讀取在web.xml文件中定義的配置信息。接下來ActionProxy會創建ActionInvocation對象。
3)??ActionInvocation是Xwork原理的(Command模式)實現部分。它會調用這個Action已定義的攔截器(before方法),Action方法,Result方法。
4)??最后,看上面流程的圖的方向,它會再執行攔截器(after方法),再回到Servlet Filter部分,最后結束并傳給用戶一個結果響應。
4、??靛色方框。這是攔截器部分,在上面的攔截器章節我們已經有了詳細的介紹。
5、??黃色方框。這是我們在開發Web應用時,需要自己開發的程序。其中包括:Action類,頁面模板,配置文件xwork.xml。
?????
WebWork?實戰和技巧
限于篇幅,我們無法在本章節給出很多詳盡的具體實例。其實,在WebWork的代碼包中,有一個非常好的演示項目——showcase,它用例子演示了WebWork的幾乎所有特性。值得初學的朋友反復研究。我們在本章節中會截取其中的部分代碼腳本。
?
1、??多視圖支持。WebWork框架天生支持多種視圖技術,包括:Jsp、FreeMarker、Velocity、Jasper Reports、XSLT,還有其它的視圖技術。這將在敏捷項目中特別有用。在我咨詢的項目中,就有一個因為技術的原因,視圖技術由最先的Jsp改為Velocity,后來又改造為FreeMarker。其中,Action類以及后臺的程序沒有做任何的改動。如果您需要一個視圖展現層技術,我在這會好不猶豫的向您推薦FreeMarker。這也是官方的推薦。
關于視圖技術的使用,首先是搭建視圖技術運行的環境。然后就是編寫頁面腳本,最后就是在xwork.xml文件中配置。Xwork配置文件中,Result的type參數,就是用來標示所使用的視圖技術。在showcase項目中,使用到的視圖技術有:Jsp、FreeMarker、Velocity、Jasper Reports。
?
2、??Action的數據驗證功能。在WebWork中,可以在三處實現數據驗證功能。一、驗證文件(例如:ActionClass-validation.xml文件)中定義數據驗證規則。二、在Action中實現com.opensymphony.xwork.Validateable接口的validate方法。三、在Action的執行方法中,硬編碼實現驗證功能。當然,在實現驗證時,我們盡可能的用前面兩中方法。
關于驗證的說明:
1)、第一種驗證需要“validation”攔截器的支持。并可以從任意層次綁定驗證文件,可以為一個Action類綁定一個驗證文件,也可以為一個具體在xwork.xml文件中的Action定義綁定一個驗證文件,可以為Action的一個屬性對象綁定一個驗證文件,甚至可以為Action的父類綁定驗證文件。
2)、WebWork為驗證文件提供了一些標準的驗證實現:例如:字段必須填寫,整型、E-mail地址等等。我們也可以使用表達式語言實現更復雜的數據驗證。
?
3、??類型轉換。前面外面一直提到過,WebWork會自動從請求的字符串參數中組裝Action需要的數據對象。這樣,就會存在一個類型轉換的問題。如果Action的字段是基本類型或是一個數據對象,WebWork會自動幫我們處理。如果Action的字段是一個集合,或者我們需要特定的類型轉換,這時,我們可以在類型轉換的定義文件(ClassName-conversion.properties)中定義轉換規則。
4、??一個Action的多個執行方法。WebWork的Action是基于Command模式的實現,在WebWork中,除了實現Action接口的execute()方法之外,Action還可以定義多個執行方法。這些方法必須要是無方法參數,并且返回返回字符串的方法。這樣我們在Url中可以用類似下面的格式訪問:actionName!methodName.action,例如user!doAdd.action,調用user Action類的doAdd方法。在最新的WebWork中,Action類甚至可以不實現Action接口。
5、??Action鏈(Action Chaining)。在WebWork中,一次用戶請求,可由多個Action共同完成。每個Action可以只實現自己本身的功能單元,這樣我們可以根據業務需要為用戶的一次請求選擇一個或多個Action功能單元來實現。在這樣的多個Action之間可以通過chain攔截器共享數據。如果請求由Action x?鏈到Action y,如果這時y需要獲得x的數據,我們就需要為Action y添加chain攔截器。
例如:在showcase中就由Action Chaining的應用。它將Action“actionChain2”鏈到另外一個Action“actionChain3”,配置文件代碼如下:
??????<?action?name?=?"actionChain2"?class?=?"com.opensymphony.webwork.showcase.actionchaining.ActionChain2"?>
??????????????????<?result?type?=?"chain"?>?actionChain3?</?result?>
????????????</?action?>
????????????<?action?name?=?"actionChain3"?class?=?"com.opensymphony.webwork.showcase.actionchaining.ActionChain3"?>
??????????????????<?result?>?/actionchaining/actionChainingResult.jsp?</?result?>
?????????</?action?>
注意:如果要加?chain?攔截器,是需要加到?actionChain3?中,而不是?actionChain2?。
?
6、??多模塊支持解決方案。?WebWork?提供了很靈活的多模塊解決方案,這樣我們可以很好的組織復雜的?Web?應用項目。
1?)可以在?xwork.xml?文件中,用?include?標簽包含另外的一個?xwork?配置文件。例如:?<include file="webwork-default.xml"/>
2?)?xwork.xml?配置文件支持?package?。我們可以將一個業務模塊的定義方到一個?package?,?package?支持繼承功能,子?package?可以享有父?package?的所有定義。
3?)可以為?package?定義一個命名空間。不同的命名空間可以定義相同的?action?名字。命名空間會用于訪問?action?的?URL?,基于這個命名空間,我們可以實現資源權限的訪問控制。
?
7、??doInput?方法。這是我們常用的小技巧,有時候請求的就是一個頁面模板,總不能為這個單獨寫一個?Action?類吧,這時我們就可以用?ActionSupport?的doInput?方法,直接返回在?Actoion?中定義為“?input?”的?result?。
8、??prepare方法。如果在Action執行之前,必須要初始化一些數據。我們可以將這些初始化的代碼方到prepare方法中。這時,Action類要實現接口com.opensymphony.xwork.Preparable,同時這個Action的定義還需要PrepareInterceptor攔截器的支持。
9、??Action的Model Driven。我們大部分的時候用得都是Action的Field Driven,即直接將Action的字段作為數據模型。Model Driven是專門為這個Action指定一個模型對象,這樣有什么好處呢?好處是在表達式語言中少了一個對象名的前綴。例如:前面值堆棧部分關于Employee的例子,要設置雇員名稱,我們必須要表達式語言例如:“employee.name”,如果這個數據是有頁面輸入得到,那么你就必須有一個Input輸入框的name為“employee.name”,因為它有關鍵字符“.”,如果Javascript腳本使用這個輸入框的名字,就會有錯誤。使用Model Driven之后,這個表達式就可以變為“name”,省去了前面的“employee.”。
10、??????????????????????Quick Start。這是WebWork2.2.2中非常激動人心的特性。它可以象perl或PHP可以快速看到程序運行結果。這樣在Web開發時,可以不用編譯Java源代碼,也不用去做打包和部署,就可以快速看到最新程序的運行結果,提高開發效率。我們可以在WebWork源碼解壓包的根目錄,輸入命令:java -jar webwork-2.2.2.jar quickstart:showcase(需要jdk1.5的支持),以Quick Start模式,運行showcase項目。
?
?
展望?WebWork?未來
這是很多人非常關心的一個問題。特別是WebWork2.2版本發布之后,官方宣稱WebWork框架將要和Struts合并。這讓一些WebWork的用戶產生了擔憂,合并之后,是不是就意味著自己在WebWork這方面技術和經驗的積累都已浪費?已使用或即將使用WebWork的項目是不是就意味著更多的風險?
答案是:完全不用擔心這些。WebWork和Struts的合并,是各取所長,然后誕生出一個更加高效的Web框架。而這個框架用得就是WebWork的優秀技術和Struts的強大社區。
合并的情況如下:
1、??產生一個新的項目Struts Action 2.0 = WebWork2.2 +?一些Struts的功能和特性。
2、??WebWork框架將會中止新功能的增加,如果有新的版本發布都會是Bug的修改。
3、??代碼、框架的開發者、社區都將移到Struts。
4、??合并的目標是致力于生產率的提高。
5、??Struts不再是一個框架,它是一個社區。
6、??Struts社區中主要有兩個Web框架。一個是基于Action模型的Struts Action;另一個是基于組件模型的Struts Shale。
總結
?
WebWork是本人工具箱中最愛的一個J2EE Web框架。本人開發過單純使用Jsp和JavaServlet的項目;也曾經自己開發過基于MVC的Web框架;在2002年開始使用Struts開發;后來也在項目中分別使用過Tapestry和Spring MVC Web框架;也在當今的AJAX潮流中隨波逐流。上面的一些技術也都非常優秀,擅用他們任何一個都會給您帶來很多生產效率的提高。但我仍然是偏愛WebWork。WebWork的與眾不同,得力于它基于OGNL的強大的數據存、取方式,得力于它那解耦的攔截器功能,得力于它那無侵入的架構設計。正是由于它,才讓Web編程變得更加的自然、簡單、靈活、高效。
轉載于:https://www.cnblogs.com/liusijia/p/4929410.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的(转自http://www.blogjava.net/moxie/archive/2006/10/20/76375.html)WebWork深入浅出的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广搜 广搜 poj 3984
- 下一篇: JSP Workshop