WebWork教程一

WebWork介紹

  WebWork是由OpenSymphony組織開發的,致力於組件化和代碼重用的拉出式MVC模式J2EE Web框架。WebWork目前最新版本是2.1,現在的WebWork2.x前身是Rickard Oberg開發的WebWork,但現在WebWork已經被拆分成了Xwork1和WebWork2兩個項目,如下示意圖所示:
 

  Xwork簡潔、靈活功能強大,它是一個標準的Command模式實現,並且完全從web層脫離出來。Xwork提供了很多核心功能:前端攔截機(interceptor),運行時表單屬性驗證,類型轉換,強大的表達式語言(OGNL – the Object Graph Notation Language),IoC(Inversion of Control倒置控制)容器等。

  WebWork2建立在Xwork之上,處理HTTP的響應和請求。WebWork2使用ServletDispatcher將HTTP請求的變成Action(業務層Action類), session(會話)application(應用程序)範圍的映射,request請求參數映射。WebWork2支持多視圖表示,視圖部分可以使用JSP, Velocity, FreeMarker, JasperReports,XML等。

  下面我們提到的WebWork將爲WebWork2,使用的版本是2.1。

 
WebWork安裝-HelloWorld

WebWork安裝

  當然,在具體開發使用介紹之前,搭建好運行環境是必備的。

  首先從https://webwork.dev.java.net/servlets/ProjectDocumentList下載最新的WebWork壓縮包,並將其解壓開來。打開解壓目錄,你將看到以下的文件和目錄:

  webwork-2.x.jar 當然就是WebWrok最新發布的Jar包

  webwork-example.war 是WebWrok自帶的很有代表性的功能演示例子,掌握它是提高你的WebWork技術水平的捷徑

  webwork-migration.jar 提供快速將1.x版本移植到2.x版本所用的類文件

  docs目錄 WebWrok的使用文檔,包括api文檔、clover文檔、單元測試(Junit)文檔等

  lib目錄 WebWork在運行或編譯時所用到的所有.jar包

  src目錄 源程序目錄

  2、WebWork是J2EE Web框架,當然要運行在Web容器中,我用的是穩定的Tomcat 4.1,關於tomcat的安裝和部署請自己搞定。

  3、用WebWork當然要將它的運行時用到的Jar包放到Web容器可以找到的ClassPath中,將步驟1介紹的webwork-2.x.jar放到你部署目錄下WEB-INFlib目錄裏,同時將WebWrok解壓目錄libcore下的所有.jar文件也拷貝到WEB-INFlib目錄,這些是運行WebWork必需要用到的jar包。

  4、瞭解Web框架的朋友都知道,一般Web框架都是通過一個JavaServlet控制器提供統一的請求入口,解析請求的url,再去調用相應的Action進行業務處理。WebWork也不例外,它要求你在web.xml文件裏配置一個派遣器ServletDispatcher,它初始化WebWrok的一些配置信息,解析XWork的Action配置信息,根據請求去組裝和調用執行相應的攔截器(Interceptor)、Action、Action Result(Action執行結果的輸出)等,具體配置如下:

代碼
……
<servlet>
<servlet-name>webwork</servlet-name>
<servlet-class>com.opensymphony.webwork.dispatcher.ServletDispatcher</servlet-class>
</servlet>
……
<servlet-mapping>
<servlet-name>webwork</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
……


  這樣,.action結尾的所有url請求將直接有ServletDispatcher去調度。下面我們寫一個經典的HelloWorld,跑一個簡單實例來驗證你運行環境是否可用,並感受一下簡單、功能強大的WebWork的開發。

  注意:如果使用WebWork自帶的標籤庫,除了配置相應的標籤庫以外,還須將com.opensymphony.webwork.views.velocity.WebWorkVelocityServlet配置到web.xml,具體可以參考webwork-example裏面的配置。
HelloWorld

  首先看下面這個程序HelloWorldAction.java:

代碼
package helloWorld

import com.opensymphony.xwork.Action;

public class HelloWorldAction implements Action{

String greeting;

public String getGreeting() {
return greeting;
}

public String execute() throws Exception {
greeting = "Hello World!";
return SUCCESS;
}

}


  HelloWorldAction是一個普通的Java類,它實現了Action這個接口。Action是一個非常簡單的接口,只有一個方法:public String execute() throws Exception; ,Action類介紹見下一節。HelloWorldAction有一個String類型字段greeting,在execute()方法中,greeting被賦值“Hello World!”,並返回String型常量SUCCESS,SUCCESS的定義詳見Action接口,這個常量代表了execute()方法執行成功,將返回成功頁面。

  返回的頁面greetings.jsp代碼如下:

代碼
<%@ taglib prefix="ww" uri="webwork" %>
<html>
<head>
<title>First WebWork Example</title>
</head>
<body>
<p><ww:property value="greeting"/></p>
</body>
</html>


  greetings.jsp很簡單的jsp頁面,它使用了WebWork自帶的標籤庫。它的作用是輸出變量“greeting”的值。這個<ww:property value="greeting"/>語句,相當於調用相應Action(HelloWorldAction)的getGreeting()方法,取得變量“greeting”的值。

  我們的HelloWorld代碼就這麼多,完了。可是,HelloWorldAction怎麼去調用、執行?執行成功它又怎麼知道返回到greetings.jsp?XWork的配置文件xwork.xml會負責將要執行的Action和展現的視圖連接起來,見xwork.xml的如下片斷:

代碼
<action name="hello" class=" helloWorld .HelloWorldAction">
<result name="success" type="dispatcher">
<param name="location">/greetings.jsp</param>
</result>
</action>


  我們先看action標籤:name=”hello”,表示我們調用這個Action的標識是hello,這樣我們可以通過下面的url訪問這個Action:…/hello.action,
例如:http://localhost:8080/webwork/hello.action;class=" helloWorld .HelloWorldAction"很好理解,這是真正調用執行的類。我們在看看result標籤:name="success",記得前面HelloWorldAction返回的字符常量SUCCESS嗎?它的值其實就是“success”,它表示Action執行成功返回success就轉向這個結果;type="dispatcher"表示執行完Action,轉向結果頁面的方式;param參數指定了結果頁面的位置:/greetings.jsp。

  代碼寫完,剩下的當然是編譯、部署。啓動tomcat服務器之後我們就可以執行了:

  在瀏覽器裏輸入你的地址:http://localhost:8080/webwork/hello.action

  你將會看到結果

Action(動作)

Action介紹

  Action在MVC模式中擔任控制部分的角色,在WebWork中使用的最多。每個請求的動作都對應於一個相應的Action,一個Action是一個獨立的工作單元和控制命令,它必需要實現XWork裏的Action接口,實現Action接口的execute()方法。Action接口的代碼如下:

代碼
package com.opensymphony.xwork;

import java.io.Serializable;

public interface Action extends Serializable {

public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";

public String execute() throws Exception;
}



  excute()方法是Action類裏最重要的部分,它執行返回String類型的值,在Action中返回的值一般使用它上面定義的標準靜態字符常量。例如:前面的HelloWorldAction返回的就是SUCCESS字符常量,真正的值當然就是“success”,它與xwork配置文件裏result標籤name的值是相對應的。它用來決定execute()方法執行完成之後,調用哪一種返回結果。字符常量的含義如下:

  SUCCESS:Action正確的執行完成,返回相應的視圖;

  NONE:表示Action正確的執行完成,但並不返回任何視圖;

  ERROR:表示Action執行失敗,返回到錯誤處理視圖;

  INPUT:Action的執行,需要從前端界面獲取參數,INPUT就是代表這個參數輸入的界面,一般在應用中,會對這些參數進行驗證,如果驗證沒有通過,將自動返回到該視圖;

  LOGIN:Action因爲用戶沒有登陸的原因沒有正確執行,將返回該登陸視圖,要求用戶進行登陸驗證。


用戶註冊例子

  下面我們將以一個用戶註冊的例子詳細介紹Action的原理:

  功能描述:一個用戶註冊頁面register.jsp,用戶可以在這個頁面裏輸入用戶註冊的基本信息(例如:姓名、密碼、Email等),輸入完成提交表單,執行用戶註冊的Action,執行成功返回成功提示的頁面(register-result.jsp)並將註冊的信息輸出。

  模型:User.java

  控制:RegisterAction.java

  視圖:register.jsp、register-result.jsp

  配置:xwork.xml

  User.java:

代碼
package register;

public class User {
  
private String username;
private String password;
private String email;
private int age;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

……

public int getAge() {
return age;
}

public int setAge(int age) {
this.age = age;
}

public String toString() {
return "username=" + username
     + ";password=" + password
     + ";email=" + email
     + ";age=" + age;
}
}



  模型User是一個普通的JavaBean,它包含了用戶註冊的字段信息,並對每個字段提供相應的set和get方法。下面我們來看看進行用戶註冊動作的RegisterAction.java:

代碼
package example.register;

import com.opensymphony.xwork.Action;

/**
* @author moxie-qac
*            [email protected]
*/
public class RegisterAction implements Action {

private User user= new User();

public User getUser() {
return this.user;
}

public String execute() {

System.out.println("Start execute 。。。。。。。。。。。。。");
System.out.println("User="+user);
//在這裏調用用戶註冊的業務邏輯,比如:將註冊信息存儲到數據庫

return SUCCESS;
}
}



  這個Action是不是特清爽?用戶註冊就這麼幾行代碼搞定,當然,我們提倡在Action裏最好不要實現業務代碼,Action的主要功能是提供從請求中取得參數的值,轉化成相應的模型,再將模型傳遞給執行業務操作的對象,比如:將註冊的用戶信息存儲到數據庫中,由業務對象執行業務操作,再返回執行的結果。爲了簡化我們省去了註冊的業務邏輯執行步驟。

  再看看我們註冊信息輸入的頁面:register.jsp

代碼
<html>
<head><title>Register Example</title></head>
<body>
<table border=0 width=97%>
<tr><td align="left">
<form name="register" action="register.action" method="post">
Username:<input type="text" name="user.username"><br>
Password:<input type="text" name="user.password"><br>
Email:<input type="text" name="user.email"><br>
Age:<input type="text" name="user.age"><br>
<input type="submit" name="Submit"><br>
</form>
</td></tr>
</table>
</body>
</html>



  register.jsp頁面其實只是一個普通的HTML頁面,它提供了一個表單,用來接受用戶輸入的註冊信息,它唯一特殊的部分就是input輸入框定義的name部分,例如:用戶姓名用的是“user. username”。這種命名方式代表什麼含義?它是必需的嗎?後面我們將會給出答案。

  RegisterAction正確執行完成之後,會將執行的結果返回到register-result.jsp頁面,由它來顯示用戶在前面頁面輸入的註冊信息。register-result.jsp代碼如下:

代碼
<%@ taglib prefix="ww" uri="webwork" %>
<html>
<head><title>Register result</title></head>
<body>
<table border=0 width=97%>
<tr>
     <td align="left">
     Congratulation,your register success!<p>
     Username:<ww:property value="user.username"/><br>
     Password:<ww:property value="user.password"/><br>
     Email:<ww:property value="user.email"/><br>
     Age:<ww:property value="user.age"/><br>
     </td>
</tr>
</table>
</body>
</html>



  這個Jsp頁面使用了WebWork的標籤庫 <ww:property />,記得HelloWorld裏的greetings.jsp嗎?它也使用了這個標籤庫。我們看這個:<ww:property value="user.username"/>

  它是一個普通的使用標籤庫語句,查看這個標籤庫的源程序,見包com.opensymphony.webwork.views.jsp裏的PropertyTag.java文件,你會發現這個類會根據value後面賦予的表達式值,去OgnlValueStack裏查找這個表達式值所對應的操作。執行這個語句OgnlValueStack會根據value的值(一個表達式)“user.username”去分別調用RegisterAction類的getUser()和User類的getUsername()方法,即:getUser().getUsername(),取得的數據就是前面註冊頁面輸入的用戶名。

  我們把“user.username”這樣的語句叫做表達式語言(Expression Language,簡稱爲EL)。它由XWork框架提供,XWork表達式語言的核心是OGNL(Object Graph Notation Language),OGNL是一種功能強大,技術成熟,應用廣泛的表達式語言,將在下面的章節有詳細介紹。

  我們在回到前面介紹的register.jsp,Input輸入框

<input type="text" name="user.username">裏用的“user.username”,現在我們可以明白,它不是隨意設置的,它是一個表達式語言,有着特殊的功能。看到這裏,不知道你心中是否有一個疑問:我們的RegisterAction是如何取得用戶註冊頁面輸入的數據呢?如果你做過Web開發,你一定會想到RegisterAction裏必需有一些從客戶端請求中獲取參數的語句,例如: 類似:String username = request.getParameter(“user. username”)的語句(request是HttpServletRequest的對象),去從request請求裏面獲取用戶輸入的參數值。可是我們這個Action裏面只有User對象簡單的get方法,並沒有其它的代碼。Xwork框架的Action是如何去實現了與Web無關?request請求的參數是怎麼傳遞到我們Action的模型User中呢?

  在回答答案之前,我們先看一看Xwork的配置文件xwork.xml:
  

代碼
<action name="register" class="example.register.RegisterAction" >
<result name="success" type="dispatcher">
<param name="location">/register-result.jsp</param>
</result>
<interceptor-ref name="params"/>
</action>



  看了前面的介紹,這段配置文件應該不難理解。用戶通過註冊頁面register.jsp輸入自己的註冊信息,提交表單到動作register.action,它將有ServletDispatcher調度,從配置文件xwork.xml裏查找與“register”匹配的Action名字,即上面配置的Action。通過這個名字XWork框架找到這個Action的類:example.register.RegisterAction,XWork框架會負責去創建這個Action類的對象並調用execute()方法進行用戶註冊操作。正確執行execute()方法返回String類型數據“success”之後,它會請求再派遣到register-result.jsp頁面。

  在這段配置文件裏,你一定注意到了它特殊的一句:<interceptor-ref name="params"/>,interceptor-ref標籤設置這個Action用到的攔截器(Interceptor),“params”引用的是配置文件中的<interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>,這個攔截器將在RegisterAction的execute()方法執行之前調用,作用是將request請求的參數值通過表達式語言設置到相應RegisterAction的模型裏。例如:register.jsp裏的<input type="text" name="user.username">,它輸入的值會由RegisterAction類的getUser()和User類的setUserName(“…”)設置到這個User模型裏。假設你在註冊頁面輸入用戶名“moxie”,提交表單ParametersInterceptor就會下面的操作:首先從請求中取得參數的名字和名字對應的值,分別爲:“user.username”和“moxie”,根據這個名字,從OgnlValueStack中取得堆棧最上面的getUser().setUsername(“moxie”)操作,即取得RegisterAction對象的User模型,並設置username屬性的值爲“moxie”。

  原來,我們的Action是通過XWork的攔截器ParametersInterceptor從提交的表單中取得請求的參數和值,再通過OgnlValueStack來執行表達式,調用Action和模型裏相應的ge或set方法,將從請求中取得的值設置到模型中去。register.jsp中Input輸入框的name="user.username"是必需要遵守OGNL的命名規則。也正是很多攔截器的使用,使得我們的Action類和Web實現了完全的解耦,讓我們的Action能如此的簡單、優雅,攔截器的原理後面章節我們也將會有詳細的介紹。

  羅索了這麼多,你一定是精通了這個用戶註冊的例子了吧!呵呵!
Field-Driven Action vs. Model-Driven Action

  Action根據FormBean的不同可以分爲二類,

  一類是Field-Driven(字段驅動的)Action

Action將直接用自己的字段來充當FormBean的功能,我們的例子就是使用這種方式。它一般用在頁面表單比較簡單的情況使用,而且可以直接用域對象作爲Action的字段,這樣就不用在另寫FormBean,減少了重複代碼。

  另一類是Model-Driven(模型驅動的)Action

  它很像Struts的FormBean,但在WebWork中,只要普通Java對象就可以充當模型部分。Model-Driven(模型驅動的)Action要求我們的Action實現com.opensymphony.xwork. ModelDriven接口,它有一個方法:Object getModel();,我們用這個方法返回我們的模型對象就可以了。

  我們可以將前面的RegisterAction.java改爲Model-Driven(模型驅動的)Action:

代碼
package example.register;

import com.opensymphony.xwork.Action;
import com.opensymphony.xwork.ModelDriven;

/**
* @author moxie-qac
*           [email protected]
*
*/
public class RegisterActionModel implements Action,ModelDriven{
private User user = new User();

public String execute() throws Exception {
System.out.println("Start execute......。。。。。。。。。。。。。。");
System.out.println("User="+user);
//在這裏調用用戶註冊的業務邏輯,比如:將註冊信息存儲到數據庫

return SUCCESS;
}

public Object getModel() {
return user;
}
}


  這時我們輸入信息的頁面也有了變化:register-model.jsp

代碼
<html>
<head><title>Register Example</title></head>
<body>
<table border=0 width=97%>
<tr><td align="left">
<form name="register" action="registerModel.action" method="post">
Username:<input type="text" name="username"><br>
Password:<input type="text" name="password"><br>
Email:<input type="text" name="email"><br>
Age:<input type="text" name="age"><br>
<input type="submit" name="Submit"><br>
</form>
</td></tr>
</table>
</body>
</html>


  我們發現,輸入框裏的命名發生了變化。它們都少了“user.”這部分信息。

  當我們採用Model-Driven(模型驅動的)Action時,它將取得模型對象保存在值堆棧中。“name="username"”就是代表直接調用模型對象的setUsername()方法。

  我們Action的在配置文件中,也要給它指定一個攔截器model-driven,它的作用就是將模型對象保存到值堆棧中。關於攔截器的介紹請看下面的章節。

  配置文件如下:

代碼
<action name="registerModel" class="example.register.RegisterActionModel">
<result name="success" type="dispatcher">
<param name="location">/register-result-model.jsp</param>
</result>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="params"/>
</action>


ActionContext(Action上下文)

ActionContext介紹

  通過上面用戶註冊例子的學習,我們知道Xwork與Web無關性,我們的Action不用去依賴於任何Web容器,不用和那些JavaServlet複雜的請求(Request)、響應(Response)關聯在一起。對請求(Request)的參數(Param),可以使用攔截器框架自動調用一些get()和set()方法設置到對應的Action的字段中。但是,僅僅取得請求參數的值就能完全滿足我們的功能要求嗎?不,在Web應用程序開發中,除了將請求參數自動設置到Action的字段中,我們往往也需要在Action裏直接獲取請求(Request)或會話(Session)的一些信息,甚至需要直接對JavaServlet Http的請求(HttpServletRequest)、響應(HttpServletResponse)操作。

  帶着這些問題,我們來看看下面的一個功能需求:

  我們需要在Action中取得request請求參數“username”的值:

代碼
ActionContext context = ActionContext.getContext();
Map params = context.getParameters();
String username = (String) params.get(“username”);


爲了實現這個功能,我們用了三個步驟:

1、 取得我們當前的ActionContext對象context,ActionContext是個什麼鼕鼕?

2、 從context對象裏獲取我們所有的請求參數,取得的卻是一個Map對象params?

3、 居然可以從我們的Map對象params裏獲取我們需要的request請求參數“username”的值。

  ActionContext(com.opensymphony.xwork.ActionContext)是Action執行時的上下文,上下文可以看作是一個容器(其實我們這裏的容器就是一個Map而已),它存放放的是Action在執行時需要用到的對象,比如:在使用WebWork時,我們的上下文放有請求的參數(Parameter)、會話(Session)、Servlet上下文(ServletContext)、本地化(Locale)信息等。

  在每次執行Action之前都會創建新的ActionContext,ActionContext是線程安全的,也就是說在同一個線程裏ActionContext裏的屬性是唯一的,這樣我的Action就可以在多線程中使用。

  我們可以通過ActionContext的靜態方法:ActionContext.getContext()來取得當前的ActionContext對象,我們看看這段代碼:

代碼
 public static ActionContext getContext() {
ActionContext context = (ActionContext) actionContext.get();
 
if (context == null) {
    OgnlValueStack vs = new OgnlValueStack();
    context = new ActionContext(vs.getContext());
    setContext(context);
}
 
return context;
}


  一般情況,我們的ActionContext都是通過:ActionContext context = (ActionContext) actionContext.get();來獲取的。我們再來看看這裏的actionContext對象的創建:static ThreadLocal actionContext = new ActionContextThreadLocal();,ActionContextThreadLocal是實現ThreadLocal的一個內部類。ThreadLocal可以命名爲“線程局部變量”,它爲每一個使用該變量的線程都提供一個變量值的副本,使每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本衝突。這樣,我們ActionContext裏的屬性只會在對應的當前請求線程中可見,從而保證它是線程安全的。

  下面我們看看怎麼通過ActionContext取得我們的HttpSession:

  Map session = ActionContext.getContext().getSession();

  原來我們取得的session卻是Map類型的對象,這是爲什麼?原來,我們的WebWork框架將與Web相關的很多對象重新進行了包裝,比如這裏就將HttpSession對象重新包裝成了一個Map對象,供我們的Action使用,而不用直接和底層的HttpSession打交道。也正是框架的包裝,讓我們的Actoion可以完全的和Web層解藕。

  如果我們的Action需要直接與JavaServlet的HttpSession、HttpServletRequest等一些對象進行操作,我們又該如何處理?請看下面的ServletActionContext。

ServletActionContext

  ServletActionContext(com.opensymphony.webwork. ServletActionContext),這個類直接繼承了我們上面介紹的ActionContext,它提供了直接與JavaServlet相關對象訪問的功能,它可以取得的對象有:

1、 javax.servlet.http.HttpServletRequest:HTTPservlet請求對象

2、 javax.servlet.http.HttpServletResponse;:HTTPservlet相應對象

3、 javax.servlet.ServletContext:Servlet 上下文信息

4、 javax.servlet.ServletConfig:Servlet配置對象

5、 javax.servlet.jsp.PageContext:Http頁面上下文

  ServletActionContext除了提供了上面這些對象訪問,它當然也繼承了它父類ActionContex的很多功能,比如:對OgnlValueStack、Action名字等的訪問。

  下面我們看看幾個簡單的例子,讓我們瞭解如何從ServletActionContext裏取得JavaServlet的相關對象:

1、 取得HttpServletRequest對象:

HttpServletRequest request = ServletActionContext. getRequest();

2、 取得HttpSession對象:

HttpSession session = ServletActionContext. getRequest().getSession();

  ServletActionContext和ActionContext有着一些重複的功能,在我們的Action中,該如何去抉擇呢?我們遵循的原則是:如果ActionContext能夠實現我們的功能,那最好就不要使用ServletActionContext,讓我們的Action儘量不要直接去訪問JavaServlet的相關對象。在使用ActionContext時有一點要注意:不要在Action的構造函數裏使用ActionContext.getContext(),因爲這個時候ActionContext裏的一些值也許沒有設置,這時通過ActionContext取得的值也許是null。
ServletDispatcher原理

  ServletDispatcher是默認的處理Web Http請求的調度器,它是一個JavaServlet,是WebWork框架的控制器。所有對Action調用的請求都將通過這個ServletDispatcher調度。它將在web.xml裏配置ServletDispatcher時指定,讓所有對WebWork 的Action(默認的是.action的後綴)的請求都對應到該調度的JavaServlet中,具體配置在前面的WebWork安裝中有介紹。

  ServletDispatcher接受客戶端的HTTP請求,將JavaServlet的很多相關對象進行包裝,再傳給我們的XWork框架,由我們的XWork框架去解析我們的xwork.xml配置文件,根據配置文件的信息,創建對應的Action,組裝並調用相應的攔截器,執行Action,返回執行結果。WebWork使用XWork的核心,主要是由這個ServletDispatcher去實現的,

  ServletDispatcher的主要功能調用如下:

  一、init()方法在服務器啓動時調用,

  1、初始化Velocity引擎

  2、檢查是否支持配置文件重新載入功能。如果webwork.configuration.xml.reload(見webwork.properties文件)設置爲true,每個request請求都將重新裝載xwork.xml配置文件。在開發環境使用將會非常方便,但在生產環境必需設置爲false。

  代碼如下:

代碼
if ("true".equalsIgnoreCase(Configuration.getString("webwork.configuration.xml.reload"))) {
  FileManager.setReloadingConfigs(true);
}


  3、設置一些文件上傳的信息,比如:上傳臨時目錄,上傳的最大字節等。都設置在webwork.properties文件裏,如果在classpath中找不到這個屬性文件,它會去讀取默認的default.properties


二、service()方法,每次客戶端的請求都將調用此方法。

  1、通過request請求取得action的命名空間(namespace,與xwork.xml配置文件裏package標籤的name對應)

  例如:/foo/bar/MyAction.action,取得的命名空間爲/foo/bar

  在xwork.xml配置文件裏應該有這一段:

  <package name="foo.bar" …….

  2、根據servlet請求的Path,解析出要調用該請求的Action的名字(actionName),例如:(../foo/bar/MyAction.action -> MyAction)

  在xwork.xml配置文件裏應該有:

  <package name="foo.bar" …….
   <Action name=” MyAction”……

  3、 創建Action上下文(extraContext)。我們前面介紹的ActionContext上下文的對象,就是在這裏設置的。它將JavaServlet相關的對象進行包裝,放入到extraContext這個Map對象裏。

代碼
   /**
     * 將所有的應用請求和servlet屬性保存到一個HashMap中,
     * @param requestMap 存放所有request請求屬性的Map
     * @param parameterMap 存放所有request請求參數的Map
     * @param sessionMap存放所有session屬性的Map
     * @param applicationMap 存放所有servlet上下文屬性的Map
     * @param request   HttpServletRequest 對象
     * @param response   HttpServletResponse 對象.
     * @param servletConfig   ServletConfig 對象.
     * @return代表Action 上下文的一個 HashMap
     */
public static HashMap createContextMap(Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response, ServletConfig servletConfig) {
HashMap extraContext = new HashMap();
extraContext.put(ActionContext.PARAMETERS, parameterMap);
extraContext.put(ActionContext.SESSION, sessionMap);
extraContext.put(ActionContext.APPLICATION, applicationMap);
extraContext.put(ActionContext.LOCALE, request.getLocale());

extraContext.put(HTTP_REQUEST, request);
extraContext.put(HTTP_RESPONSE, response);
extraContext.put(SERVLET_CONFIG, servletConfig);
extraContext.put(COMPONENT_MANAGER, request.getAttribute("DefaultComponentManager"));

// helpers to get access to request/session/application scope
extraContext.put("request", requestMap);
extraContext.put("session", sessionMap);
extraContext.put("application", applicationMap);
extraContext.put("parameters", parameterMap);

AttributeMap attrMap = new AttributeMap(extraContext);
extraContext.put("attr", attrMap);

return extraContext;
}


  下面我們來看看它是如何將request請求的參數和session進行包裝的:

代碼
protected Map getParameterMap(HttpServletRequest request) throws IOException {
return request.getParameterMap();
}


這個方法比較簡單,它直接調用了HttpServletRequest的方法getParameterMap(),將所有request請求的參數封裝到一個Map中。

代碼
protected Map getSessionMap(HttpServletRequest request) {
return new SessionMap(request);
}


  這個方法取得所有Session中的屬性,它調用了com.opensymphony.webwork.dispatcher. SessionMap類,這個類實現了Map接口,在entrySet()方法中列舉Session的所有屬性,存放在Set中。

  4、根據前面獲得的namespace、actionName、extraContext,創建一個ActonProxy

代碼
  ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);


  默認的proxy是com.opensymphony.xwork.DefaultActionProxy,在它的構造函數會進行下面的操作:

  1)、根據namespace、actionName讀取xwork.xml配置文件裏這個Action的所有配置信息。

  2)、創建ActionInvocation

代碼
  invocation = ActionProxyFactory.getFactory().createActionInvocation(this, extraContext);


  默認的invocation是com.opensymphony.xwork.DefaultActionInvocation,它的構造函數操作有:

  a) 由com.opensymphony.xwork.ObjectFactory創建我們配置文件描述的Action對象。再將這個Action對象存放入OgnlValueStack中。記得我們前面用戶註冊的例子嗎?當用戶提交表達時它會有表達式語言向OgnlValueStack取得Action對象的字段,再把輸入框的數據設置到對應的Action字段中,這個Action對象就是在這個時候進棧的。

  b) 傳入extraContext參數,創建與ActionInvocation對應的Action上下文(ActionContext)。記得我們在介紹ActionContext的最後,提出了一個需要注意的地方:不要在Action構造函數中調用ActionContext.getContext()。現在應該能明白,原來是Action對象實例在ActionContext對象實例之前創建的,所有這樣取得ActionContext容器對象就有可能會返回null

  c) 取得這個Action對應的所有攔截器(Interceptor),存放入java.util.Iterator對象中。

  5、執行proxy的execute()方法,這個方法最核心的語句是:retCode = invocation.invoke();, invocation對象的invoke()方法它遍歷並執行這個Action對應的所有攔截器,執行Action對應的方法(默認的是execute()),根據Action執行返回的值去調用執行相應的Result(返回結果處理)的方法。
發佈了21 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章