小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

WebWork教程-0.90版

 思奇劍 2006-11-10

WebWork介紹

WebWork是由OpenSymphony組織開發(fā)的,致力于組件化和代碼重用的拉出式MVC模式J2EE Web框架。WebWork目前最新版本是2.1,現(xiàn)在的WebWork2.x前身是Rickard Oberg開發(fā)的WebWork,但現(xiàn)在WebWork已經(jīng)被拆分成了Xwork1WebWork2兩個(gè)項(xiàng)目,如下示意圖所示:

 

 

WebWork1

XWork1

WebWork2

 

Web

Non-web

 

 

 

 

 

 

 

 

 


Xwork簡潔、靈活功能強(qiáng)大,它是一個(gè)標(biāo)準(zhǔn)的Command模式實(shí)現(xiàn),并且完全從web層脫離出來。Xwork提供了很多核心功能:前端攔截機(jī)(interceptor),運(yùn)行時(shí)表單屬性驗(yàn)證,類型轉(zhuǎn)換,強(qiáng)大的表達(dá)式語言(OGNL – the Object Graph Notation Language),IoCInversion of Control倒置控制)容器等。

WebWork2建立在Xwork之上,處理HTTP的響應(yīng)和請(qǐng)求。WebWork2使用ServletDispatcherHTTP請(qǐng)求的變成Action(業(yè)務(wù)層Action), session(會(huì)話)application(應(yīng)用程序)范圍的映射,request請(qǐng)求參數(shù)映射。WebWork2支持多視圖表示,視圖部分可以使用JSP, Velocity, FreeMarker, JasperReports,XML等。

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

 

WebWork安裝-HelloWorld

WebWork安裝

當(dāng)然,在具體開發(fā)使用介紹之前,搭建好運(yùn)行環(huán)境是必備的。

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

webwork-2.x.jar 當(dāng)然就是WebWrok最新發(fā)布的Jar

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

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

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

lib目錄 WebWork在運(yùn)行或編譯時(shí)所用到的所有.jar

src目錄 源程序目錄

2WebWorkJ2EE Web框架,當(dāng)然要運(yùn)行在Web容器中,我用的是穩(wěn)定的Tomcat 4.1,關(guān)于tomcat的安裝和部署請(qǐng)自己搞定。

3、用WebWork當(dāng)然要將它的運(yùn)行時(shí)用到的Jar包放到Web容器可以找到的ClassPath中,將步驟1介紹的webwork-2.x.jar放到你部署目錄下WEB-INF\lib目錄里,同時(shí)將WebWrok解壓目錄lib\core下的所有.jar文件也拷貝到WEB-INF\lib目錄,這些是運(yùn)行WebWork必需要用到的jar包。

4、了解Web框架的朋友都知道,一般Web框架都是通過一個(gè)JavaServlet控制器提供統(tǒng)一的請(qǐng)求入口,解析請(qǐng)求的url,再去調(diào)用相應(yīng)的Action進(jìn)行業(yè)務(wù)處理。WebWork也不例外,它要求你在web.xml文件里配置一個(gè)派遣器ServletDispatcher,它初始化WebWrok的一些配置信息,解析XWorkAction配置信息,根據(jù)請(qǐng)求去組裝和調(diào)用執(zhí)行相應(yīng)的攔截器(Interceptor)、Action、Action Result(Action執(zhí)行結(jié)果的輸出)等,具體配置如下:

……

<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結(jié)尾的所有url請(qǐng)求將直接有ServletDispatcher去調(diào)度。下面我們寫一個(gè)經(jīng)典的HelloWorld,跑一個(gè)簡單實(shí)例來驗(yàn)證你運(yùn)行環(huán)境是否可用,并感受一下簡單、功能強(qiáng)大的WebWork的開發(fā)。

注意:如果使用WebWork自帶的標(biāo)簽庫,除了配置相應(yīng)的標(biāo)簽庫以外,還須將com.opensymphony.webwork.views.velocity.WebWorkVelocityServlet配置到web.xml,具體可以參考webwork-example里面的配置。

HelloWorld

首先看下面這個(gè)程序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是一個(gè)普通的Java類,它實(shí)現(xiàn)了Action這個(gè)接口。Action是一個(gè)非常簡單的接口,只有一個(gè)方法:public String execute() throws Exception; ,Action類介紹見下一節(jié)。HelloWorldAction有一個(gè)String類型字段greeting,在execute()方法中,greeting被賦值“Hello World!”,并返回String型常量SUCCESS,SUCCESS的定義詳見Action接口,這個(gè)常量代表了execute()方法執(zhí)行成功,將返回成功頁面。

返回的頁面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自帶的標(biāo)簽庫。它的作用是輸出變量“greeting”的值。這個(gè)<ww:property value="greeting"/>語句,相當(dāng)于調(diào)用相應(yīng)ActionHelloWorldAction)的getGreeting()方法,取得變量“greeting”的值。

我們的HelloWorld代碼就這么多,完了??墒?,HelloWorldAction怎么去調(diào)用、執(zhí)行?執(zhí)行成功它又怎么知道返回到greetings.jsp?XWork的配置文件xwork.xml會(huì)負(fù)責(zé)將要執(zhí)行的Action和展現(xiàn)的視圖連接起來,見xwork.xml的如下片斷:

<action name="hello" class=" helloWorld .HelloWorldAction">

    <result name="success" type="dispatcher">

       <param name="location">/greetings.jsp</param>

    </result>

</action>

我們先看action標(biāo)簽:name=”hello”,表示我們調(diào)用這個(gè)Action的標(biāo)識(shí)是hello,這樣我們可以通過下面的url訪問這個(gè)Action…/hello.action,
例如:http://localhost:8080/webwork/hello.actionclass=" helloWorld .HelloWorldAction"很好理解,這是真正調(diào)用執(zhí)行的類。我們?cè)诳纯?/span>result標(biāo)簽:name="success",記得前面HelloWorldAction返回的字符常量SUCCESS嗎?它的值其實(shí)就是“success”,它表示Action執(zhí)行成功返回success就轉(zhuǎn)向這個(gè)結(jié)果;type="dispatcher"表示執(zhí)行完Action,轉(zhuǎn)向結(jié)果頁面的方式;param參數(shù)指定了結(jié)果頁面的位置:/greetings.jsp。

代碼寫完,剩下的當(dāng)然是編譯、部署。啟動(dòng)tomcat服務(wù)器之后我們就可以執(zhí)行了:

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

你將會(huì)看到如下結(jié)果:

Action(動(dòng)作)

Action介紹

ActionMVC模式中擔(dān)任控制部分的角色,在WebWork中使用的最多。每個(gè)請(qǐng)求的動(dòng)作都對(duì)應(yīng)于一個(gè)相應(yīng)的Action,一個(gè)Action是一個(gè)獨(dú)立的工作單元和控制命令,它必需要實(shí)現(xiàn)XWork里的Action接口,實(shí)現(xiàn)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類里最重要的部分,它執(zhí)行返回String類型的值,在Action中返回的值一般使用它上面定義的標(biāo)準(zhǔn)靜態(tài)字符常量。例如:前面的HelloWorldAction返回的就是SUCCESS字符常量,真正的值當(dāng)然就是“success”,它與xwork配置文件里result標(biāo)簽name的值是相對(duì)應(yīng)的。它用來決定execute()方法執(zhí)行完成之后,調(diào)用哪一種返回結(jié)果。字符常量的含義如下:

SUCCESSAction正確的執(zhí)行完成,返回相應(yīng)的視圖;

NONE:表示Action正確的執(zhí)行完成,但并不返回任何視圖;

ERROR:表示Action執(zhí)行失敗,返回到錯(cuò)誤處理視圖;

INPUTAction的執(zhí)行,需要從前端界面獲取參數(shù),INPUT就是代表這個(gè)參數(shù)輸入的界面,一般在應(yīng)用中,會(huì)對(duì)這些參數(shù)進(jìn)行驗(yàn)證,如果驗(yàn)證沒有通過,將自動(dòng)返回到該視圖;

LOGINAction因?yàn)橛脩魶]有登陸的原因沒有正確執(zhí)行,將返回該登陸視圖,要求用戶進(jìn)行登陸驗(yàn)證。

用戶注冊(cè)例子

下面我們將以一個(gè)用戶注冊(cè)的例子詳細(xì)介紹Action的原理:

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

模型: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是一個(gè)普通的JavaBean,它包含了用戶注冊(cè)的字段信息,并對(duì)每個(gè)字段提供相應(yīng)的setget方法。下面我們來看看進(jìn)行用戶注冊(cè)動(dòng)作的RegisterAction.java

package example.register;

 

import com.opensymphony.xwork.Action;

 

/**

 * @author moxie-qac

 *         achqian@yahoo.com.cn

 */

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);

       //在這里調(diào)用用戶注冊(cè)的業(yè)務(wù)邏輯,比如:將注冊(cè)信息存儲(chǔ)到數(shù)據(jù)庫

   

       return SUCCESS;

    }

}

這個(gè)Action是不是特清爽?用戶注冊(cè)就這么幾行代碼搞定,當(dāng)然,我們提倡在Action里最好不要實(shí)現(xiàn)業(yè)務(wù)代碼,Action的主要功能是提供從請(qǐng)求中取得參數(shù)的值,轉(zhuǎn)化成相應(yīng)的模型,再將模型傳遞給執(zhí)行業(yè)務(wù)操作的對(duì)象,比如:將注冊(cè)的用戶信息存儲(chǔ)到數(shù)據(jù)庫中,由業(yè)務(wù)對(duì)象執(zhí)行業(yè)務(wù)操作,再返回執(zhí)行的結(jié)果。為了簡化我們省去了注冊(cè)的業(yè)務(wù)邏輯執(zhí)行步驟。

再看看我們注冊(cè)信息輸入的頁面: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頁面其實(shí)只是一個(gè)普通的HTML頁面,它提供了一個(gè)表單,用來接受用戶輸入的注冊(cè)信息,它唯一特殊的部分就是input輸入框定義的name部分,例如:用戶姓名用的是“user. username”。這種命名方式代表什么含義?它是必需的嗎?后面我們將會(huì)給出答案。

RegisterAction正確執(zhí)行完成之后,會(huì)將執(zhí)行的結(jié)果返回到register-result.jsp頁面,由它來顯示用戶在前面頁面輸入的注冊(cè)信息。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>

這個(gè)Jsp頁面使用了WebWork的標(biāo)簽庫 <ww:property />,記得HelloWorld里的greetings.jsp嗎?它也使用了這個(gè)標(biāo)簽庫。我們看這個(gè):<ww:property value="user.username"/>
它是一個(gè)普通的使用標(biāo)簽庫語句,查看這個(gè)標(biāo)簽庫的源程序,見包
com.opensymphony.webwork.views.jsp
里的PropertyTag.java文件,你會(huì)發(fā)現(xiàn)這個(gè)類會(huì)根據(jù)value后面賦予的表達(dá)式值,去OgnlValueStack里查找這個(gè)表達(dá)式值所對(duì)應(yīng)的操作。執(zhí)行這個(gè)語句OgnlValueStack會(huì)根據(jù)value的值(一個(gè)表達(dá)式)“user.username”去分別調(diào)用RegisterAction類的getUser()User類的getUsername()方法,即:getUser().getUsername(),取得的數(shù)據(jù)就是前面注冊(cè)頁面輸入的用戶名。

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

我們?cè)诨氐角懊娼榻B的register.jsp,Input輸入框
<input type="text" name="user.username">
里用的“user.username”,現(xiàn)在我們可以明白,它不是隨意設(shè)置的,它是一個(gè)表達(dá)式語言,有著特殊的功能。看到這里,不知道你心中是否有一個(gè)疑問:我們的RegisterAction是如何取得用戶注冊(cè)頁面輸入的數(shù)據(jù)呢?如果你做過Web開發(fā),你一定會(huì)想到RegisterAction里必需有一些從客戶端請(qǐng)求中獲取參數(shù)的語句,例如: 類似:String username = request.getParameter(“user. username”)的語句(requestHttpServletRequest的對(duì)象),去從request請(qǐng)求里面獲取用戶輸入的參數(shù)值??墒俏覀冞@個(gè)Action里面只有User對(duì)象簡單的get方法,并沒有其它的代碼。Xwork框架的Action是如何去實(shí)現(xiàn)了與Web無關(guān)?request請(qǐng)求的參數(shù)是怎么傳遞到我們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>

看了前面的介紹,這段配置文件應(yīng)該不難理解。用戶通過注冊(cè)頁面register.jsp輸入自己的注冊(cè)信息,提交表單到動(dòng)作register.action,它將有ServletDispatcher調(diào)度,從配置文件xwork.xml里查找與“register”匹配的Action名字,即上面配置的Action。通過這個(gè)名字XWork框架找到這個(gè)Action的類:example.register.RegisterActionXWork框架會(huì)負(fù)責(zé)去創(chuàng)建這個(gè)Action類的對(duì)象并調(diào)用execute()方法進(jìn)行用戶注冊(cè)操作。正確執(zhí)行execute()方法返回String類型數(shù)據(jù)“success”之后,它會(huì)請(qǐng)求再派遣到register-result.jsp頁面。

在這段配置文件里,你一定注意到了它特殊的一句:<interceptor-ref name="params"/>,interceptor-ref標(biāo)簽設(shè)置這個(gè)Action用到的攔截器(Interceptor),“params”引用的是配置文件中的<interceptor name="params" class="
com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
,這個(gè)攔截器將在RegisterActionexecute()方法執(zhí)行之前調(diào)用,作用是將request請(qǐng)求的參數(shù)值通過表達(dá)式語言設(shè)置到相應(yīng)RegisterAction的模型里。例如:register.jsp里的<input type="text" name="user.username">,它輸入的值會(huì)由RegisterAction類的getUser()User類的setUserName(“…”)設(shè)置到這個(gè)User模型里。假設(shè)你在注冊(cè)頁面輸入用戶名“moxie”,提交表單ParametersInterceptor就會(huì)下面的操作:首先從請(qǐng)求中取得參數(shù)的名字和名字對(duì)應(yīng)的值,分別為:“user.username”和“moxie”,根據(jù)這個(gè)名字,從OgnlValueStack中取得堆棧最上面的getUser().setUsername(“moxie”)操作,即取得RegisterAction對(duì)象的User模型,并設(shè)置username屬性的值為“moxie”。

原來,我們的Action是通過XWork的攔截器ParametersInterceptor從提交的表單中取得請(qǐng)求的參數(shù)和值,再通過OgnlValueStack來執(zhí)行表達(dá)式,調(diào)用Action和模型里相應(yīng)的geset方法,將從請(qǐng)求中取得的值設(shè)置到模型中去。register.jspInput輸入框的name="user.username"是必需要遵守OGNL的命名規(guī)則。也正是很多攔截器的使用,使得我們的Action類和Web實(shí)現(xiàn)了完全的解耦,讓我們的Action能如此的簡單、優(yōu)雅,攔截器的原理后面章節(jié)我們也將會(huì)有詳細(xì)的介紹。

羅索了這么多,你一定是精通了這個(gè)用戶注冊(cè)的例子了吧!呵呵!

Field-Driven Action vs. Model-Driven Action

Action根據(jù)FormBean的不同可以分為二類,

一類是Field-Driven(字段驅(qū)動(dòng)的)Action

   Action將直接用自己的字段來充當(dāng)FormBean的功能,我們的例子就是使用這種方式。它一般用在頁面表單比較簡單的情況使用,而且可以直接用域?qū)ο笞鳛?/span>Action的字段,這樣就不用在另寫FormBean,減少了重復(fù)代碼。

另一類是Model-Driven(模型驅(qū)動(dòng)的)Action

它很像StrutsFormBean,但在WebWork中,只要普通Java對(duì)象就可以充當(dāng)模型部分。Model-Driven(模型驅(qū)動(dòng)的)Action要求我們的Action實(shí)現(xiàn)com.opensymphony.xwork. ModelDriven接口,它有一個(gè)方法:Object getModel();,我們用這個(gè)方法返回我們的模型對(duì)象就可以了。

我們可以將前面的RegisterAction.java改為Model-Driven(模型驅(qū)動(dòng)的)Action

package example.register;

 

import com.opensymphony.xwork.Action;

import com.opensymphony.xwork.ModelDriven;

 

/**

 * @author moxie-qac

 *         achqian@yahoo.com.cn

 *

 */

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);

       //在這里調(diào)用用戶注冊(cè)的業(yè)務(wù)邏輯,比如:將注冊(cè)信息存儲(chǔ)到數(shù)據(jù)庫

   

       return SUCCESS;

    }

   

    public Object getModel() {

       return user;

    }

}

這時(shí)我們輸入信息的頁面也有了變化: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>

我們發(fā)現(xiàn),輸入框里的命名發(fā)生了變化。它們都少了“user.”這部分信息。

當(dāng)我們采用Model-Driven(模型驅(qū)動(dòng)的)Action時(shí),它將取得模型對(duì)象保存在值堆棧中?!?/span>name="username"”就是代表直接調(diào)用模型對(duì)象的setUsername()方法。

我們Action的在配置文件中,也要給它指定一個(gè)攔截器model-driven,它的作用就是將模型對(duì)象保存到值堆棧中。關(guān)于攔截器的介紹請(qǐng)看下面的章節(jié)。

配置文件如下:

<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介紹

通過上面用戶注冊(cè)例子的學(xué)習(xí),我們知道XworkWeb無關(guān)性,我們的Action不用去依賴于任何Web容器,不用和那些JavaServlet復(fù)雜的請(qǐng)求(Request)、響應(yīng)(Response)關(guān)聯(lián)在一起。對(duì)請(qǐng)求(Request)的參數(shù)(Param),可以使用攔截器框架自動(dòng)調(diào)用一些get()set()方法設(shè)置到對(duì)應(yīng)的Action的字段中。但是,僅僅取得請(qǐng)求參數(shù)的值就能完全滿足我們的功能要求嗎?不,在Web應(yīng)用程序開發(fā)中,除了將請(qǐng)求參數(shù)自動(dòng)設(shè)置到Action的字段中,我們往往也需要在Action里直接獲取請(qǐng)求(Request)或會(huì)話(Session)的一些信息,甚至需要直接對(duì)JavaServlet Http的請(qǐng)求(HttpServletRequest)、響應(yīng)(HttpServletResponse)操作。

帶著這些問題,我們來看看下面的一個(gè)功能需求:

我們需要在Action中取得request請(qǐng)求參數(shù)“username”的值:

   ActionContext context = ActionContext.getContext();

Map params = context.getParameters();

String username = (String) params.get(“username”);

為了實(shí)現(xiàn)這個(gè)功能,我們用了三個(gè)步驟:

1、 取得我們當(dāng)前的ActionContext對(duì)象context,ActionContext是個(gè)什么冬冬?

2、 context對(duì)象里獲取我們所有的請(qǐng)求參數(shù),取得的卻是一個(gè)Map對(duì)象params

3、 居然可以從我們的Map對(duì)象params里獲取我們需要的request請(qǐng)求參數(shù)“username”的值。

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

在每次執(zhí)行Action之前都會(huì)創(chuàng)建新的ActionContext,ActionContext是線程安全的,也就是說在同一個(gè)線程里ActionContext里的屬性是唯一的,這樣我的Action就可以在多線程中使用。

我們可以通過ActionContext的靜態(tài)方法:ActionContext.getContext()來取得當(dāng)前的ActionContext對(duì)象,我們看看這段代碼:

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();來獲取的。我們?cè)賮砜纯催@里的actionContext對(duì)象的創(chuàng)建:static ThreadLocal actionContext = new ActionContextThreadLocal();,ActionContextThreadLocal是實(shí)現(xiàn)ThreadLocal的一個(gè)內(nèi)部類。ThreadLocal可以命名為“線程局部變量”,它為每一個(gè)使用該變量的線程都提供一個(gè)變量值的副本,使每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)和其它線程的副本沖突。這樣,我們ActionContext里的屬性只會(huì)在對(duì)應(yīng)的當(dāng)前請(qǐng)求線程中可見,從而保證它是線程安全的。

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

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

原來我們?nèi)〉玫?/span>session卻是Map類型的對(duì)象,這是為什么?原來,我們的WebWork框架將與Web相關(guān)的很多對(duì)象重新進(jìn)行了包裝,比如這里就將HttpSession對(duì)象重新包裝成了一個(gè)Map對(duì)象,供我們的Action使用,而不用直接和底層的HttpSession打交道。也正是框架的包裝,讓我們的Actoion可以完全的和Web層解藕。

如果我們的Action需要直接與JavaServletHttpSession、HttpServletRequest等一些對(duì)象進(jìn)行操作,我們又該如何處理?請(qǐng)看下面的ServletActionContext

ServletActionContext

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

1、 javax.servlet.http.HttpServletRequestHTTPservlet請(qǐng)求對(duì)象

2、 javax.servlet.http.HttpServletResponse;HTTPservlet相應(yīng)對(duì)象

3、 javax.servlet.ServletContextServlet 上下文信息

4、 javax.servlet.ServletConfigServlet配置對(duì)象

5、 javax.servlet.jsp.PageContextHttp頁面上下文

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

下面我們看看幾個(gè)簡單的例子,讓我們了解如何從ServletActionContext里取得JavaServlet的相關(guān)對(duì)象:

1、 取得HttpServletRequest對(duì)象:

HttpServletRequest request = ServletActionContext. getRequest();

2、 取得HttpSession對(duì)象:

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

ServletActionContextActionContext有著一些重復(fù)的功能,在我們的Action中,該如何去抉擇呢?我們遵循的原則是:如果ActionContext能夠?qū)崿F(xiàn)我們的功能,那最好就不要使用ServletActionContext,讓我們的Action盡量不要直接去訪問JavaServlet的相關(guān)對(duì)象。在使用ActionContext時(shí)有一點(diǎn)要注意:不要在Action的構(gòu)造函數(shù)里使用ActionContext.getContext(),因?yàn)檫@個(gè)時(shí)候ActionContext里的一些值也許沒有設(shè)置,這時(shí)通過ActionContext取得的值也許是null

 

 

 

ServletDispatcher原理

ServletDispatcher是默認(rèn)的處理Web Http請(qǐng)求的調(diào)度器,它是一個(gè)JavaServlet,是WebWork框架的控制器。所有對(duì)Action調(diào)用的請(qǐng)求都將通過這個(gè)ServletDispatcher調(diào)度。它將在web.xml里配置ServletDispatcher時(shí)指定,讓所有對(duì)WebWork Action(默認(rèn)的是.action的后綴)的請(qǐng)求都對(duì)應(yīng)到該調(diào)度的JavaServlet中,具體配置在前面的WebWork安裝中有介紹。

ServletDispatcher接受客戶端的HTTP請(qǐng)求,將JavaServlet的很多相關(guān)對(duì)象進(jìn)行包裝,再傳給我們的XWork框架,由我們的XWork框架去解析我們的xwork.xml配置文件,根據(jù)配置文件的信息,創(chuàng)建對(duì)應(yīng)的Action,組裝并調(diào)用相應(yīng)的攔截器,執(zhí)行Action,返回執(zhí)行結(jié)果。WebWork使用XWork的核心,主要是由這個(gè)ServletDispatcher去實(shí)現(xiàn)的,

 

ServletDispatcher的主要功能調(diào)用如下:

一、init()方法在服務(wù)器啟動(dòng)時(shí)調(diào)用,

   1、初始化Velocity引擎

2、檢查是否支持配置文件重新載入功能。如果webwork.configuration.xml.reload(見webwork.properties文件)設(shè)置為true,每個(gè)request請(qǐng)求都將重新裝載xwork.xml配置文件。在開發(fā)環(huán)境使用將會(huì)非常方便,但在生產(chǎn)環(huán)境必需設(shè)置為false。

代碼如下:

if ("true".equalsIgnoreCase(Configuration.getString("webwork.configuration.xml.reload"))) {

FileManager.setReloadingConfigs(true);

}

 3、設(shè)置一些文件上傳的信息,比如:上傳臨時(shí)目錄,上傳的最大字節(jié)等。都設(shè)置在webwork.properties文件里,如果在classpath中找不到這個(gè)屬性文件,它會(huì)去讀取默認(rèn)的default.properties

 

二、service()方法,每次客戶端的請(qǐng)求都將調(diào)用此方法。

 1、通過request請(qǐng)求取得action的命名空間(namespace,與xwork.xml配置文件里package標(biāo)簽的name對(duì)應(yīng))

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

xwork.xml配置文件里應(yīng)該有這一段:

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

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

xwork.xml配置文件里應(yīng)該有:

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

       <Action name=” MyAction”……

 

3、 創(chuàng)建Action上下文(extraContext)。我們前面介紹的ActionContext上下文的對(duì)象,就是在這里設(shè)置的。它將JavaServlet相關(guān)的對(duì)象進(jìn)行包裝,放入到extraContext這個(gè)Map對(duì)象里。

/**

     * 將所有的應(yīng)用請(qǐng)求和servlet屬性保存到一個(gè)HashMap中,

    * @param requestMap 存放所有request請(qǐng)求屬性的Map

     * @param parameterMap 存放所有request請(qǐng)求參數(shù)的Map

     * @param sessionMap存放所有session屬性的Map

     * @param applicationMap 存放所有servlet上下文屬性的Map

     * @param request HttpServletRequest 對(duì)象

     * @param response  HttpServletResponse 對(duì)象.

     * @param servletConfig  ServletConfig 對(duì)象.

     * @return代表Action 上下文的一個(gè) 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請(qǐng)求的參數(shù)和session進(jìn)行包裝的:

protected Map getParameterMap(HttpServletRequest request) throws IOException {

        return request.getParameterMap();

}

這個(gè)方法比較簡單,它直接調(diào)用了HttpServletRequest的方法getParameterMap(),將所有request請(qǐng)求的參數(shù)封裝到一個(gè)Map中。

 

protected Map getSessionMap(HttpServletRequest request) {

        return new SessionMap(request);

}

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

 

4、根據(jù)前面獲得的namespaceactionNameextraContext,創(chuàng)建一個(gè)ActonProxy

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

默認(rèn)的proxycom.opensymphony.xwork.DefaultActionProxy,在它的構(gòu)造函數(shù)會(huì)進(jìn)行下面的操作:1)、根據(jù)namespace、actionName讀取xwork.xml配置文件里這個(gè)Action的所有配置信息。

2)、創(chuàng)建ActionInvocation

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

默認(rèn)的invocationcom.opensymphony.xwork.DefaultActionInvocation,它的構(gòu)造函數(shù)操作有:

a)         com.opensymphony.xwork.ObjectFactory創(chuàng)建我們配置文件描述的Action對(duì)象。再將這個(gè)Action對(duì)象存放入OgnlValueStack中。記得我們前面用戶注冊(cè)的例子嗎?當(dāng)用戶提交表達(dá)時(shí)它會(huì)有表達(dá)式語言向OgnlValueStack取得Action對(duì)象的字段,再把輸入框的數(shù)據(jù)設(shè)置到對(duì)應(yīng)的Action字段中,這個(gè)Action對(duì)象就是在這個(gè)時(shí)候進(jìn)棧的。

b)        傳入extraContext參數(shù),創(chuàng)建與ActionInvocation對(duì)應(yīng)的Action上下文(ActionContext)。記得我們?cè)诮榻BActionContext的最后,提出了一個(gè)需要注意的地方:不要在Action構(gòu)造函數(shù)中調(diào)用ActionContext.getContext()?,F(xiàn)在應(yīng)該能明白,原來是Action對(duì)象實(shí)例在ActionContext對(duì)象實(shí)例之前創(chuàng)建的,所有這樣取得ActionContext容器對(duì)象就有可能會(huì)返回null

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

 

5、執(zhí)行proxyexecute()方法,這個(gè)方法最核心的語句是:retCode = invocation.invoke();, invocation對(duì)象的invoke()方法它遍歷并執(zhí)行這個(gè)Action對(duì)應(yīng)的所有攔截器,執(zhí)行Action對(duì)應(yīng)的方法(默認(rèn)的是execute()),根據(jù)Action執(zhí)行返回的值去調(diào)用執(zhí)行相應(yīng)的Result(返回結(jié)果處理)的方法。

Action的單元測(cè)試

理解了ServletDispatcher,我們就明白了整個(gè)框架調(diào)用執(zhí)行的順序。Action雖然是與Web無關(guān),可是它的創(chuàng)建、參數(shù)設(shè)置、執(zhí)行與我們的WebWork、XWork緊密關(guān)聯(lián)在一起,有我們的控制器ServletDispatcher去統(tǒng)一調(diào)度,那我們?nèi)绾稳?duì)Action進(jìn)行獨(dú)立的單元測(cè)試呢?

請(qǐng)看下面的例子:使用單元測(cè)試框架JUnit對(duì)register.User. RegisterAction做單元測(cè)試

example.register. RegisterActionTesttestExecuteWithProxyFactory()方法:

 

public void testExecuteWithProxyFactory() throws Exception{

      

       Map params = new HashMap();

       params.put("user.username","Moxie");

       params.put("user.password","mypassword");

       params.put("user.email","achqian@yahoo.com.cn");

       params.put("user.age",new Integer(23));

       Map extraContext = new HashMap();

       extraContext.put(ActionContext.PARAMETERS,params);

      

       ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy("example", "register", extraContext);

       proxy.setExecuteResult(false);

       assertEquals(proxy.execute(),"success");

      

       RegisterAction action = (RegisterAction) proxy.getAction();

       assertEquals(action.getUser().getUsername(),"Moxie");

       assertEquals(action.getUser().getAge(),23);

    }

下面解說這個(gè)方法:

1、 對(duì)象params表示請(qǐng)求參數(shù)的Map,在它里面設(shè)置了注冊(cè)用戶的信息。extraContext當(dāng)然就是我們ActionContext上下文的容器,它里面保存了放置請(qǐng)求參數(shù)的對(duì)象params

2、 創(chuàng)建我們的ActionProxy,它傳入的參數(shù)有:“example”-這個(gè)Action的命名空間,“register”-Action對(duì)應(yīng)的名字,extraContext-存放Actin上下文里的對(duì)象,,執(zhí)行并將它返回的值與“success”比較,測(cè)試Action是否能正確執(zhí)行完成。注意:proxy.setExecuteResult(false);,因?yàn)槲覀兪菃卧獪y(cè)試,所以Action執(zhí)行完成就可以了,不用再去調(diào)用結(jié)果響應(yīng)的操作,故將是否執(zhí)行結(jié)果設(shè)置為“false”。

3、 Action正確執(zhí)行完成之后,我們也可以測(cè)試現(xiàn)在Action的字段里的數(shù)據(jù)是否按照我們預(yù)期的要求正確設(shè)置。從ActionProxy對(duì)象里取得執(zhí)行的Action,即RegisterAction對(duì)象,再取得它的User模型,將其數(shù)據(jù)與前面設(shè)置參數(shù)的數(shù)據(jù)進(jìn)行比較,判斷它是否等于我們預(yù)期設(shè)置的數(shù)值。

   

Result Type

前面我們學(xué)習(xí)了ServletDispatcher,它是WebWork框架機(jī)制的核心。它和Action在我們MVC模式中,扮演著控制器的角色,MVC模式通過控制器實(shí)現(xiàn)了我們模型和視圖的分離。WebWork提供了多種活靈活視圖展現(xiàn)方式。

我們先看看前面用戶注冊(cè)例子的展現(xiàn)方式:我們使用的是JspWebWork自帶的標(biāo)簽庫,Action對(duì)應(yīng)的視圖當(dāng)然是在xwork.xml配置文件里設(shè)置:

<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>

ResultAction執(zhí)行完返回的一個(gè)字符串常量,它表示Action執(zhí)行完成的狀態(tài),比如:執(zhí)行成功、執(zhí)行失敗等。在我們前面Action的介紹中,詳細(xì)介紹了它默認(rèn)的標(biāo)準(zhǔn)Result,當(dāng)然Result我們也可以自己定義,只要是一個(gè)字符串常量就可以了。

Result的值在xwork.xml配置文件里就是result標(biāo)簽里“name”的值,name="success"表示Action執(zhí)行成功,返回“success”就對(duì)應(yīng)此標(biāo)簽的配置,進(jìn)行視圖輸出。

type”就是我們的Result TypeResult Type是一個(gè)類,它在Action執(zhí)行完成并返回Result之后,決定采用哪一種視圖技術(shù),將執(zhí)行結(jié)果展現(xiàn)給用戶。我們輸出的類型是:type="dispatcher",它對(duì)應(yīng)com.opensymphony.webwork.dispatcher.ServletDispatcherResult這個(gè)類,它將執(zhí)行結(jié)果通過javax.servlet.RequestDispatcherforward()include()方法調(diào)度到Jsp頁面展現(xiàn)。

我們可以自己開發(fā)Result Type,實(shí)現(xiàn)我們需要的視圖展現(xiàn)方式。Result Type必需要實(shí)現(xiàn)com.opensymphony.xwork..Result接口。在WebWork中,它已經(jīng)為我們提供了很多Result Type,實(shí)現(xiàn)了視圖部分對(duì)JSP, Velocity, FreeMarker, JasperReports,XML等的支持,具體如下表格:

 

 

 

 

 

 

Result Type

Nname

Class

Dispatcher

dispatcher

com.opensymphony.webwork.dispatcher.ServletDispatcherResult

Redirect

redirect

com.opensymphony.webwork.dispatcher.ServletRedirectResult

Action Chaining

chain

com.opensymphony.xwork.ActionChainResult

Velocity

velocity

com.opensymphony.webwork.dispatcher.VelocityResult

FreeMarker

freemarker

com.opensymphony.webwork.views.freemarker.FreemarkerResult

JasperReports

jasper

com.opensymphony.webwork.views.jasperreports.JasperReportsResult

XML/XSL

xslt

com.opensymphony.webwork.views.xslt.XSLTResult

HttpHeader

 

com.opensymphony.webwork.dispatcher.HttpHeaderResult

 

Dispatcher通過javax.servlet.RequestDispatcherforward()include()方法調(diào)度到頁面展現(xiàn),這樣的頁面一般是Jsp頁面。

 

參數(shù)(Parameters)

是否必需

 

location

執(zhí)行完成之后轉(zhuǎn)向的位置

parse

默認(rèn)的是“true”,如果設(shè)置為“false”,location參數(shù)將不會(huì)被OGNL表達(dá)式語言解析

例子:

<result name="success" type="dispatcher">

              <param name="location">register-result.jsp</param>

       </result>

也可以簡單寫成這樣:

   <result name="success" type="dispatcher">register-result.jsp</result>

 

Redirect將響應(yīng)重定向到瀏覽器指定的位置,它將會(huì)導(dǎo)致Action執(zhí)行完成的數(shù)據(jù)丟失或不再可用。它在程序里是通過調(diào)用javax.servlet.http.HttpServletResponse.sendRedirect(String location)方法,將響應(yīng)定向到參數(shù)location指定的、新的url中。

 

參數(shù)(Parameters)

是否必需

 

location

執(zhí)行完成之后轉(zhuǎn)向的位置

parse

默認(rèn)的是“true”,如果設(shè)置為“false”,location參數(shù)將不會(huì)被OGNL表達(dá)式語言解析

例子

       <result name="success" type="redirect">

           <param name="location">foo.jsp</param>

           <param name="parse">false</param>

</result>

 

Action Chaining一種特殊的視圖結(jié)果,將Action執(zhí)行完之后鏈接到另一個(gè)Action中繼續(xù)執(zhí)行。新的Action使用上一個(gè)Action的上下文(ActionContext)。

 

參數(shù)(Parameters)

是否必需

 

actionName

將要被鏈接的Action名字

namespace

被鏈接的Action的命名空間(namespace),如果不設(shè)置,默認(rèn)的即是當(dāng)前的命名空間

例子:

<result name="success" type="chain">

    <param name="actionName">bar</param>

    <param name="namespace">/foo</param>

</result>

 

將要調(diào)用的Action如下:

<action name="bar" class="myPackage.barAction">

    ...

</action>

 

Velocity它類似Jsp的執(zhí)行環(huán)境(使用JavaServlet容器),將Velocity模板轉(zhuǎn)化成數(shù)據(jù)流的形式,直接通過JavaServlet輸出。

 

參數(shù)(Parameters)

是否必需

 

location

執(zhí)行完成之后轉(zhuǎn)向的位置(一般是.vm頁面)

parse

默認(rèn)的是“true”,如果設(shè)置為“false”,location參數(shù)將不會(huì)被OGNL表達(dá)式語言解析

例子:

<result name="success" type="velocity">

    <param name="location">foo.vm</param>

</result>

 

FreeMarkerFreeMarker是一個(gè)純Java模板引擎;一個(gè)普通的基于模板生成文本的工具,它只能應(yīng)用在Web應(yīng)用環(huán)境中。

 

參數(shù)(Parameters)

是否必需

 

location

執(zhí)行完成之后轉(zhuǎn)向的位置

parse

默認(rèn)的是“true”,如果設(shè)置為“false”,location參數(shù)將不會(huì)被OGNL表達(dá)式語言解析

contentType

如果不指定,默認(rèn)的是"text/html"

例子:

<result name="success" type="freemarker">foo.ftl</result>

 

JasperReportsAction執(zhí)行的結(jié)果通過JasperReports報(bào)表形式輸出,可以指定JasperReports支持的輸出格式(PDF、HTML、XLS、CSV、XML等),默認(rèn)是通過PDF格式輸出。

參數(shù)(Parameters)

是否必需

 

location

執(zhí)行完成之后轉(zhuǎn)向的位置

parse

默認(rèn)的是“true”,如果設(shè)置為“false”,location參數(shù)將不會(huì)被OGNL表達(dá)式語言解析

dataSource

它是Action的一個(gè)字段(通常是一個(gè)List),OGNL表達(dá)式被用來去value stackOgnlValueStack)重新找回這個(gè)dataSource

format

報(bào)表生成的數(shù)據(jù)格式,默認(rèn)的是pdf

例子:

<result name="success" type="jasper">

    <param name="location">foo.jasper</param>

    <param name="dataSource">mySource</param>

    <param name="format">CSV</param>

</result>

 

或者默認(rèn)的pdf格式

<result name="success" type="jasper">

    <param name="location">foo.jasper</param>

    <param name="dataSource">mySource</param>

</result>

 

XML/XSL將結(jié)果轉(zhuǎn)換為xml輸出

 

參數(shù)(Parameters)

是否必需

 

location

執(zhí)行完成之后轉(zhuǎn)向的位置

parse

默認(rèn)的是“true”,如果設(shè)置為“false”,location參數(shù)將不會(huì)被OGNL表達(dá)式語言解析

例子:

<result name="success" type="xslt">foo.xslt</result>               

 

 

 

 

 


 

表達(dá)式與言ELOGNL

OGNL介紹

OGNLObject-Graph Navigation Language的縮寫,它是一種功能強(qiáng)大的表達(dá)式語言(Expression Language,簡稱為EL),通過它簡單一致的表達(dá)式語法,可以存取對(duì)象的任意屬性,調(diào)用對(duì)象的方法,遍歷整個(gè)對(duì)象的結(jié)構(gòu)圖,實(shí)現(xiàn)字段類型轉(zhuǎn)化等功能。它使用相同的表達(dá)式去存取對(duì)象的屬性。

XWork遵循“不要重復(fù)地發(fā)明同一個(gè)輪子”的理論,它的表達(dá)式語言核心用的就是這個(gè)OGNL。我們先來看看一個(gè)簡單的例子:

還記得我們用戶注冊(cè)的那個(gè)例子嗎?我們輸入框的name用到的名字就是OGNL的表達(dá)式,比如:用戶名的輸入框:“<input type="text" name="user.username">”,在用戶注冊(cè)成功之后我們要顯示用戶注冊(cè)的信息,用了“<ww:property value="user.username"/>”。Input輸入框里的“user.username”,它解析成Java語句為:getUser().setUsername();,property標(biāo)簽里的“user.username”解析為Java語句:getUser.getUsername();

我們的兩個(gè)表達(dá)式都是相同的,但前一個(gè)保存對(duì)象屬性的值,后一個(gè)是取得對(duì)象屬性的值。表達(dá)式語言簡單、易懂卻又功能強(qiáng)大,關(guān)于OGNL更多的介紹可以去http://www.,那里有很詳細(xì)的文檔。

值堆棧-OgnlValueStack

OGNL在框架中的應(yīng)用,最主要是支持我們的值堆棧(Value Stack)——OgnlValueStack,它主要的功能是通過表達(dá)式語言來存取對(duì)象的屬性。用戶界面輸入數(shù)據(jù),它會(huì)根據(jù)保存表達(dá)式將數(shù)據(jù)依次保存到它堆棧的對(duì)象中,業(yè)務(wù)操作完成,結(jié)果數(shù)據(jù)會(huì)通過表達(dá)式被獲取、輸出。

還記得我們用戶注冊(cè)的例子嗎?下面我們用一段程序來演示它向OgnlValueStack中保存、取得數(shù)據(jù)的步驟:

// DemoRegisterValueStack

package example.register;

 

import com.opensymphony.xwork.util.OgnlValueStack;

 

/**

 * @author moxie-qac

 *         achqian@yahoo.com.cn

 *

 */

public class DemoRegisterValueStack {

    public void demo(){

       RegisterAction action = new RegisterAction();

       OgnlValueStack valueStack= new OgnlValueStack();

       valueStack.push(action);

      

       valueStack.setValue("user.username","Moxie");

        System.out.println("username = "+valueStack.findValue("user.username"));

    }

 

    public static void main(String[] args) {

DemoRegisterValueStack demoValueStack = new DemoRegisterValueStack();

       demoValueStack.demo();

    }

}

我們來看一看它的demo()方法:

1、 創(chuàng)建我們的ActionRegisterAction)類的對(duì)象action,將action對(duì)象壓入堆棧valueStack中。在WebWrokAction的創(chuàng)建、入棧是在DefaultActionInvocation構(gòu)造函數(shù)中進(jìn)行的,詳細(xì)介紹見:ServletDispatcher原理。

2、 通過表達(dá)式語言,調(diào)用堆棧對(duì)象的get()、set()方法,設(shè)置該對(duì)象的值。

   public void setValue(String expr, Object value)

   語句:valueStack.setValue("user.username","Moxie");

   的作用等同于:action.getUser().setUsername("Moxie");

3、 通過表達(dá)式語言,去堆棧對(duì)象中查找我們前面保存的值,并在控制臺(tái)打印。valueStack.findValue("user.username")等同與語句
action.getUser().getUsername()

最后控制臺(tái)打印的結(jié)果:

       username = Moxie

CompoundRoot

OgnlValueStack中,一個(gè)堆棧其實(shí)是一個(gè)List。查看OgnlValueStack你會(huì)發(fā)現(xiàn),堆棧就是com.opensymphony.xwork.util.CompoundRoot類的對(duì)象:

public class CompoundRoot extends ArrayList {

    //~ Constructors /////////////////////////////////////

    public CompoundRoot() {

    }

    public CompoundRoot(List list) {

        super(list);

    }

    //~ Methods ////////////////////////////////////////////

    public CompoundRoot cutStack(int index) {

        return new CompoundRoot(subList(index, size()));

    }

    public Object peek() {

        return get(0);

    }

    public Object pop() {

        return remove(0);

    }

    public void push(Object o) {

        add(0, o);

    }

}

我們通過表達(dá)式向堆棧對(duì)象操作時(shí),我們并不知道堆棧中有哪些對(duì)象。OgnlValueStack會(huì)根據(jù)堆棧由上向下的順序(先入棧在下面,最后入棧在最上面)依次去查找與表達(dá)式匹配的對(duì)象方法,找到即進(jìn)行相應(yīng)的存取操作。假設(shè)后面對(duì)象也有相同的方法,將不會(huì)被調(diào)用。

下面我們看一個(gè)對(duì)OgnlValueStack操作的程序,它主要演示了如何對(duì)Map對(duì)象的存取和OgnlValueStack堆棧的原理:

/*

 * Created on 2004-6-15

 * DemoGroupValueStack.java

 */

package example.register;

 

import com.opensymphony.xwork.util.OgnlValueStack;

 

/**

 * @author moxie-qac

 *         achqian@yahoo.com.cn

 *

 */

public class DemoGroupValueStack {

   

    public void demoAction(){

       DemoGroupAction action = new DemoGroupAction();

       OgnlValueStack valueStack= new OgnlValueStack();

       valueStack.push(action);

      

       User zhao = new User();

       zhao.setUsername("zhao");

       zhao.setEmail("zhao@yahoo.com.cn");

      

       User qian = new User();

       qian.setUsername("qian");

       qian.setEmail("qian@yahoo.com.cn");

      

       valueStack.setValue("users[‘zhao‘]",zhao);

       valueStack.setValue("users[‘qian‘]",qian);

      

      

       System.out.println("users[‘zhao‘] = "+valueStack.findValue("users[‘zhao‘]"));

       System.out.println("users[‘qian‘] = "+valueStack.findValue("users[‘qian‘]"));

       System.out.println("users size = "+valueStack.findValue("users.size"));

      

       System.out.println("allUserName[0] = "+valueStack.findValue("allUserName[0]"));

    }

   

    public void demoModels(){

      

       User model_a = new User();

       model_a.setUsername("model_a");

       User model_b = new User();

       model_b.setUsername("model_b");

       User model_c = new User();

       model_c.setUsername("model_c");

      

       OgnlValueStack valueStack= new OgnlValueStack();

       valueStack.push(model_a);

       valueStack.push(model_b);

       valueStack.push(model_c);

      

       System.out.println("username = "+valueStack.findValue("username"));

       System.out.println("[1].username = "+valueStack.findValue("[1].username"));

       System.out.println("[0].toString = "+valueStack.findValue("[0]"));

       System.out.println("[1].toString = "+valueStack.findValue("[1]"));

       System.out.println("[2].toString = "+valueStack.findValue("[2]"));

      

    }

    public static void main(String[] args) {

       DemoGroupValueStack demoValueStack = new DemoGroupValueStack();

       demoValueStack.demoAction();

       demoValueStack.demoModels();

    }

}

 

/*

 * Created on 2004-6-15

 * DemoAction.java

 */

package example.register;

 

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

 

/**

 * @author moxie-qac

 *        achqian@yahoo.com.cn

 *

 */

public class DemoGroupAction {

   

    private Map users = new HashMap();

   

    public Map getUsers(){

       return this.users;

    }

   

    public List getAllUserName(){

       return new ArrayList(users.keySet());

    }

    public String execute(){

       //執(zhí)行業(yè)務(wù)操作

       return null;

    }

    public String toString(){

       return users.toString();

    }

}

注意:1、Map屬性的存取,它的表達(dá)式語言如:users[‘zhao‘],注意它用’’來引用HashMapkey字符串。

2、demoModels()方法演示了OgnlValueStack中堆棧的原理,請(qǐng)?zhí)貏e注意它的[0].toString[1].toString、[2].toString,它們依次調(diào)用堆棧中對(duì)象的toString()方法,并逐一的減少堆棧最上面的對(duì)象。

控制臺(tái)輸出的結(jié)果如下:

users[‘zhao‘] = username=zhao;password=null;email=zhao@yahoo.com.cn;age=0

users[‘qian‘] = username=qian;password=null;email=qian@yahoo.com.cn;age=0

users size = 2

allUserName[0] = qian

 

username = model_c

[1].username = model_b

[0].toString = [username=model_c;password=null;email=null;age=0, username=model_b;password=null;email=null;age=0, username=model_a;password=null;email=null;age=0]

[1].toString = [username=model_b;password=null;email=null;age=0, username=model_a;password=null;email=null;age=0]

[2].toString = [username=model_a;password=null;email=null;age=0]


 

Interceptor(攔截器)框架

Interceptor(攔截器)將Action共用的行為獨(dú)立出來,在Action執(zhí)行前后運(yùn)行。這也就是我們所說的AOPAspect Oriented Programming,面向切面編程),它是分散關(guān)注的編程方法,它將通用需求功能從不相關(guān)類之中分離出來;同時(shí),能夠使得很多類共享一個(gè)行為,一旦行為發(fā)生變化,不必修改很多類,只要修改這個(gè)行為就可以。

Interceptor將很多功能從我們的Action中獨(dú)立出來,大量減少了我們Action的代碼,獨(dú)立出來的行為具有很好的重用性。XWork、WebWork的許多功能都是有Interceptor實(shí)現(xiàn),可以在配置文件中組裝Action用到的Interceptor,它會(huì)按照你指定的順序,在Action執(zhí)行前后運(yùn)行。Interceptor在框架中的應(yīng)用如下圖所示:

 

 

當(dāng)你提交對(duì)Aciton(默認(rèn)是.action結(jié)尾的Url)的請(qǐng)求時(shí),ServletDispatcher會(huì)根據(jù)你的請(qǐng)求,去調(diào)度并執(zhí)行相應(yīng)的Action。在Action執(zhí)行之前,調(diào)用被 Interceptor截取,InterceptorAction執(zhí)行前后運(yùn)行。

我們?cè)谟脩糇?cè)的例子中就使用了取得Request請(qǐng)求參數(shù)的攔截器,配置文件中<interceptor-ref name="params"/>將攔截器params組裝到RegisterAction中?!?/span>params”在我們的webwork-default.xml配置文件中有定義,webwork-default.xml中攔截器的定義如下:

<interceptors>

            <interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>

            <interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/>

            <interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/>

            <interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/>

            <interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>

            <interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/>

            <interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/>

            <interceptor name="token" class="com.opensymphony.webwork.interceptor.TokenInterceptor"/>

            <interceptor name="token-session" class="com.opensymphony.webwork.interceptor.TokenSessionStoreInterceptor"/>

            <interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>

            <interceptor name="workflow" class="com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor"/>

            <interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/>

            <interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/>

            <interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/>

            <interceptor-stack name="defaultStack">

                <interceptor-ref name="static-params"/>

                <interceptor-ref name="params"/>

                <interceptor-ref name="conversionError"/>

            </interceptor-stack>

            <interceptor-stack name="validationWorkflowStack">

                <interceptor-ref name="defaultStack"/>

                <interceptor-ref name="validation"/>

                <interceptor-ref name="workflow"/>

            </interceptor-stack>

        </interceptors>

這些都時(shí)有框架提供的默認(rèn)的Interceptor,下面我來看看Interceptor使用的步驟:

1、 創(chuàng)建一個(gè)自己需要的Interceptor類,它必需實(shí)現(xiàn)
com.opensymphony.xwork.interceptor.Interceptor
接口,具體的開發(fā)見下面的Interceptor的原理。

2、 在配置文件(xwork..xml)中申明這個(gè)Interceptor類,它放在標(biāo)簽<interceptor />中,同是<interceptor />標(biāo)簽嵌入在<interceptors />標(biāo)簽內(nèi)部。

3、 創(chuàng)建Interceptor棧,使用標(biāo)簽:<interceptor-stack />,讓一組Interceptor可以按次序調(diào)用。(可選)

4、 指定Action所要用到的Interceptor(前面申明過的),可以用<interceptor-ref /><default-interceptor-ref />標(biāo)簽。前面的標(biāo)簽指定某個(gè)Action所用到的Interceptor,如果Action沒有被用<interceptor-ref />指定Interceptor,它將使用<default-interceptor-ref />指定的Interceptor。

框架中給我們提供了很多實(shí)用的Interceptor,它的定義上面已經(jīng)給出,它的具體功能如下:

l         timer:記錄Action執(zhí)行的時(shí)間,并做為日志信息輸出;

l         logger:在日志信息中輸出要執(zhí)行的Action信息;

l         chain:將前一個(gè)執(zhí)行結(jié)束的Action屬性設(shè)置到當(dāng)前的Action中。它被用在ResultType為“chain”指定結(jié)果的Action中,該結(jié)果Action對(duì)象會(huì)從OgnlValueStack中獲得前一個(gè)Action對(duì)應(yīng)的屬性,它實(shí)現(xiàn)Action鏈之間的數(shù)據(jù)傳遞;

l         static-params:將xwork.xml配置文件里定義的Action參數(shù),設(shè)置到對(duì)應(yīng)的Action中。Action參數(shù)使用<param />標(biāo)簽,是<action />標(biāo)簽的直接子元素。我們這里定義的Action類必需實(shí)現(xiàn)com.opensymphony.xwork.config.entities. Parameterizable接口;

l         params:將Request請(qǐng)求的參數(shù)設(shè)置到相應(yīng)Action對(duì)象的屬性中,用戶注冊(cè)例子用到過這個(gè)攔截器;

l         model-driven:如果Action實(shí)現(xiàn)ModelDriven接口,它將getModel()取得的模型對(duì)象存入OgnlValueStack中;

l         component:激活組件功能支持,讓注冊(cè)過的組件在當(dāng)前Action中可用,即為Action提供IoC(依賴倒轉(zhuǎn)控制)框架的支持;

l         token:核對(duì)當(dāng)前Action請(qǐng)求(request)的有效標(biāo)識(shí),防止重復(fù)提交Action請(qǐng)求(request)。

l         token-session:功能同上,但是當(dāng)提交無效的Action請(qǐng)求標(biāo)識(shí)時(shí),它會(huì)將請(qǐng)求數(shù)據(jù)保存到session中。

l         validation:實(shí)現(xiàn)使用xml配置文件({Action}-validation.xml)對(duì)Action屬性值進(jìn)行驗(yàn)證,詳細(xì)請(qǐng)看后面介紹的驗(yàn)證框架。

l         workflow:調(diào)用Action類的驗(yàn)證功能,假設(shè)Action使用ValidationAware實(shí)現(xiàn)驗(yàn)證(ActionSupport提供此功能),如果驗(yàn)證沒有通過,workflow會(huì)將請(qǐng)求返回到input視圖(Action<result />中定義的)。

l         servlet-config:提供Action直接對(duì)HttpServletRequestHttpServletResponseJavaServlet api的訪問,Action要實(shí)現(xiàn)相應(yīng)的接口,例如:ServletRequestAwareServletResponseAware。如果必需要提供對(duì)JavaServlet api的訪問,我們建議使用ServletActionContext,在前面ActionContext章節(jié)中有介紹。

l         prepare:在Action執(zhí)行之前調(diào)用Actionprepare()方法,這個(gè)方法是用來準(zhǔn)備Action執(zhí)行之前要做的工作。它要求我們的Action必需實(shí)現(xiàn)com.opensymphony.xwork. Preparable接口

l         conversionError:用來處理框架進(jìn)行類型轉(zhuǎn)化(Type Conversion)時(shí)的出錯(cuò)信息。它將存儲(chǔ)在ActionContext中的類型轉(zhuǎn)化(Type Conversion)錯(cuò)誤信息轉(zhuǎn)化成相應(yīng)的Action字段的錯(cuò)誤信息,保存在堆棧中。根據(jù)需要,可以將這些錯(cuò)誤信息在視圖中顯示出來。

Interceptor的原理

下面我們來看看Interceptor是如何實(shí)現(xiàn)在Action執(zhí)行前后調(diào)用的:

ActionInterceptor在框架中的執(zhí)行,是由ActionInvocation對(duì)象調(diào)用的。它是用方法:String invoke() throws Exception;來實(shí)現(xiàn)的,它首先會(huì)依次調(diào)用Action對(duì)應(yīng)的Interceptor,執(zhí)行完成所有的Interceptor之后,再去調(diào)用Action的方法,代碼如下:

if (interceptors.hasNext()) {

Interceptor interceptor = (Interceptor) interceptors.next();

resultCode = interceptor.intercept(this);

} else {

     if (proxy.getConfig().getMethodName() == null) {

resultCode = getAction().execute();

} else {

        resultCode = invokeAction(getAction(), proxy.getConfig());

}

}

它會(huì)在攔截器棧中遍歷Interceptor,調(diào)用Interceptor方法:
String intercept(ActionInvocation invocation) throws Exception;。

我們一直都提到,Interceptor是在Action前后執(zhí)行,可是從上面的代碼我們看到的卻是執(zhí)行完所有Interceptorintercept()方法之后再去調(diào)用我們的Action?!霸?/span>Action前后執(zhí)行”是如何實(shí)現(xiàn)的呢?我們來看看抽象類AroundInterceptorintercept()實(shí)現(xiàn):

public String intercept(ActionInvocation invocation) throws Exception {

        String result = null;

 

        before(invocation);

        result = invocation.invoke();

        after(invocation, result);

 

        return result;

    }

原來在intercept()方法又對(duì)ActionInvocationinvoke()方法進(jìn)行遞歸調(diào)用,ActionInvocation循環(huán)嵌套在intercept()中,一直到語句result = invocation.invoke();執(zhí)行結(jié)束,即:Action執(zhí)行完并返回結(jié)果result,這時(shí)Interceptor對(duì)象會(huì)按照剛開始執(zhí)行的逆向順序依次執(zhí)行結(jié)束。這樣before()方法將在Action執(zhí)行前調(diào)用,after()方法在Action執(zhí)行之后運(yùn)行。

驗(yàn)證框架

WebWork提供了在Action執(zhí)行之前,對(duì)輸入數(shù)據(jù)的驗(yàn)證功能,它使用了其核心XWork的驗(yàn)證框架。提供了如下功能:

1、 可配置的驗(yàn)證文件。它的驗(yàn)證文件是一個(gè)獨(dú)立的XML配置文件,對(duì)驗(yàn)證的添加、修改只需更改配置文件,無需編譯任何的Class

2、 驗(yàn)證文件和被驗(yàn)證的對(duì)象完全解藕。驗(yàn)證對(duì)象是普通的JavaBean就可以了(可以是FormBean、域?qū)ο蟮龋?,它們不需?shí)現(xiàn)任何額外的方法或繼承額外的類。

3、 多種不同的驗(yàn)證方式。因?yàn)樗?yàn)證功能是可以繼承的,所以可以用多種不同的方式指定驗(yàn)證文件,比如:通過父類的Action、通過Action、通過Action的方法、通過Action所使用的對(duì)象,等等。

4、 強(qiáng)大的表達(dá)式驗(yàn)證。它使用了OGNL的表達(dá)式語言,提供強(qiáng)大的表達(dá)式驗(yàn)證功能。

5、 同時(shí)支持服務(wù)器端和客戶端驗(yàn)證。

為用戶注冊(cè)添加驗(yàn)證功能

下面我們來看看如何為用戶注冊(cè)添加驗(yàn)證功能:

1、 注冊(cè)我們的驗(yàn)證類型

WebWork為不同的驗(yàn)證要求提供不同的驗(yàn)證類型。一個(gè)驗(yàn)證類型,一般是有一個(gè)類來提供。這個(gè)類必須實(shí)現(xiàn)接口:com.opensymphony.xwork.validator.Validator,但我們?cè)趯懽约旱尿?yàn)證類型時(shí),無需直接實(shí)現(xiàn)Validator接口,它有抽象類可供直接使用如ValidatorSupport、FieldValidatorSupport等。

驗(yàn)證類型在使用之前,必須要在ValidatorFactorycom.opensymphony.xwork.validator. ValidatorFactory)中注冊(cè)。可以有二種方法實(shí)現(xiàn)驗(yàn)證類型的注冊(cè)。一、寫程序代碼進(jìn)行注冊(cè),它使用ValidatorFactory類的靜態(tài)方法:registerValidator(String name, String className)。二、使用配置文件validators.xml進(jìn)行注冊(cè),要求把文件validators.xml放到ClassPath的跟目錄中(/WEB-INF/classes)。但在實(shí)際開發(fā)中,一般都使用第二中注冊(cè)方法。我們的驗(yàn)證類型注冊(cè)如下:

<validators>

    <validator name="required" class="com.opensymphony.xwork.validator.validators.RequiredFieldValidator"/>

    <validator name="requiredstring" class="com.opensymphony.xwork.validator.validators.RequiredStringValidator"/>

    <validator name="int" class="com.opensymphony.xwork.validator.validators.IntRangeFieldValidator"/>

    <validator name="date" class="com.opensymphony.xwork.validator.validators.DateRangeFieldValidator"/>

    <validator name="expression" class="com.opensymphony.xwork.validator.validators.ExpressionValidator"/>

    <validator name="fieldexpression" class="com.opensymphony.xwork.validator.validators.FieldExpressionValidator"/>

    <validator name="email" class="com.opensymphony.xwork.validator.validators.EmailValidator"/>

    <validator name="url" class="com.opensymphony.xwork.validator.validators.URLValidator"/>

    <validator name="visitor" class="com.opensymphony.xwork.validator.validators.VisitorFieldValidator"/>

    <validator name="conversion" class="com.opensymphony.xwork.validator.validators.ConversionErrorFieldValidator"/>

    <validator name="stringlength" class="com.opensymphony.xwork.validator.validators.StringLengthFieldValidator"/>

</validators>

注冊(cè)驗(yàn)證類型的配置文件非常簡單。它使用標(biāo)簽<validator>提供名-值對(duì)的形式注冊(cè)。這樣我們的驗(yàn)證文件就可以直接引用它的名字。

2、 開啟Action的驗(yàn)證功能

 如果Action要使用驗(yàn)證框架的驗(yàn)證功能,它必須在配置文件中指定攔截器“validation”,它的定義如下:

<interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>。

我們的驗(yàn)證文件必須以ActionName-validation.xml格式命名,它必須被放置到與這個(gè)Action相同的包中。你也可以為這個(gè)Action通過別名的方式指定驗(yàn)證文件,它的命名格式為:ActionName-aliasname-validation.xml?!?/span>ActionName ”是我們Action的類名;“aliasname”是我們?cè)谂渲梦募?/span>xwork.xml)中定義這個(gè)Action所用到的名稱。這樣,同一個(gè)Action類,在配置文件中的不同定義就可以對(duì)應(yīng)不同的驗(yàn)證文件。驗(yàn)證框架也會(huì)根據(jù)Action的繼承結(jié)構(gòu)去查找Action的父類驗(yàn)證文件,如果找到它會(huì)去執(zhí)行這個(gè)父類的驗(yàn)證。

 

3、 實(shí)現(xiàn)我們的驗(yàn)證文件:RegisterActionSupport-validation.xml

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN" "http://www./xwork/xwork-validator-1.0.dtd">

<validators>

    <field name="user.username">

    <field-validator type="requiredstring">

            <message>You must enter a value for username.</message>

        </field-validator>

    </field>

    <field name="user.password">

    <field-validator type="requiredstring">

            <message>You must enter a value for password.</message>

        </field-validator>

        <field-validator type="fieldexpression">

            <param name="expression">user.password == verifyPassword</param>

            <message>Passwords don‘t match.</message>

        </field-validator>

    </field>

    <field name="user.email">

    <field-validator type="email">

            <message>You must enter a valid email.</message>

        </field-validator>

    </field>

    <field name="user.age">

    <field-validator type="int">

            <param name="min">6</param>

            <param name="max">100</param>

            <message>Age must be between ${min} and ${max}, current value is ${user.age}.</message>

        </field-validator>

    </field>

</validators>

說明:

1)、<field>標(biāo)簽代表一個(gè)字段,它的屬性“name”和頁面輸入框的“name”屬性必需完全一致,其實(shí)它也就是我們的表達(dá)式語言。

2)、<field-validator>標(biāo)簽定義我們的驗(yàn)證規(guī)則,type屬性的值就是就是我們前面定義的驗(yàn)證類型。

3)、驗(yàn)證文件中,字段的數(shù)據(jù)是通過表達(dá)式語言從我們的值堆棧(OgnlValueStack)中取得,一般是ActionModel對(duì)象。例如:我們的字段“user.age”,它會(huì)通過ActiongetUser().getAge()來取得用戶輸入的年齡,再來根據(jù)驗(yàn)證的類型“int”和最大值最小值的參數(shù)來判斷輸入的數(shù)據(jù)是否能通過驗(yàn)證。

4)、不管驗(yàn)證是否通過,我們的Action都會(huì)執(zhí)行,但如果驗(yàn)證沒有通過,它不會(huì)調(diào)用Actionexecute()方法。

 

4、 顯示Action的驗(yàn)證錯(cuò)誤信息

如果用戶輸入的數(shù)據(jù)驗(yàn)證沒有通過,我們需重新返回輸入頁面,并給出錯(cuò)誤信息提示。攔截器棧“validationWorkflowStack”為我們實(shí)現(xiàn)了這個(gè)功能。它首先驗(yàn)證用戶輸入的數(shù)據(jù),如果驗(yàn)證沒有通過將不執(zhí)行我們Actionexecute()方法,而是將請(qǐng)求重新返回到輸入頁面。

我們的xwork.xml配置文件如下:

<action name="registerSupport" class="example.register.RegisterActionSupport" >

           <result name="success" type="dispatcher">

              <param name="location">/register-result.jsp</param>

           </result>

           <result name="input" type="dispatcher">

              <param name="location">/registerSupport.jsp</param>

           </result>

           <interceptor-ref name="validationWorkflowStack"/>

       </action>

 

通過接口ValidationAware我們可以獲得類級(jí)別或字段級(jí)別的驗(yàn)證錯(cuò)誤信息,這個(gè)錯(cuò)誤信息也就是我們驗(yàn)證文件中<message>標(biāo)簽里的數(shù)據(jù)。ActionSupport類已實(shí)現(xiàn)了此接口,這樣在應(yīng)用中我們的Action只要繼承ActionSupport類就可以了。RegisterActionSupport.java代碼如下:

package example.register;

 

import com.opensymphony.xwork.ActionSupport;

 

/**

 * @author moxie-qac

 *         achqian@yahoo.com.cn

 *

 */

public class RegisterActionSupport extends ActionSupport {

 

    private User user= new User();

    private String verifyPassword;

   

    public User getUser(){

       return this.user;

    }

   

    public String execute(){

       //在這里調(diào)用用戶注冊(cè)的業(yè)務(wù)邏輯,比如:將注冊(cè)信息存儲(chǔ)到數(shù)據(jù)庫

       return SUCCESS;

    }

 

    public String getVerifyPassword(){

       return this.verifyPassword;

    }

   

    public void setVerifyPassword(String verPassword){

       this.verifyPassword = verPassword;

    }

}

我們WebWorkUI標(biāo)簽庫直接提供了驗(yàn)證錯(cuò)誤信息顯示功能。如果字段級(jí)別的驗(yàn)證沒有通過,它會(huì)在輸入框上方顯示驗(yàn)證文件定義的錯(cuò)誤提示信息。我們將用戶輸入的頁面更改如下:

registerSupport.jsp

<%@ taglib uri="webwork" prefix="ww" %>

<html>

<head><title>Register Example</title></head>

<body>

<table border=0 width=97%>

<tr><td align="left">

    <ww:form name="‘test‘" action="‘/example/registerSupport.action‘" method="‘POST‘">

            <ww:textfield label="‘Username‘" name="‘user.username‘" required="true"/>

            <ww:textfield label="‘Password‘" name="‘user.password‘" required="true"/>

            <ww:textfield label="‘VerifyPassword‘" name="‘verifyPassword‘" required="true"/>

            <ww:textfield label="‘Email‘" name="‘user.email‘" required="true"/>

            <ww:textfield label="‘Age‘" name="‘user.age‘" required="true"/>

            <ww:submit value="‘Submit‘"/>

         </ww:form>

</td></tr>

</table>

</body>

</html>

我們上面的例子使用的是服務(wù)器端驗(yàn)證。WebWork也為我們提供了方便的客戶端驗(yàn)證。它將驗(yàn)證自動(dòng)生成JavaScript腳本。如果要使用客戶端驗(yàn)證只需改變相應(yīng)的驗(yàn)證類型就可以了(輸入頁面的表單必需使用<ww:form>標(biāo)簽,并設(shè)置屬性“validate="true"”)。具體的驗(yàn)證類型可以在WebWork的包com.opensymphony.webwork.validators中找到。


 

XWork配置詳述

XWork配置文件是以“xwork”命名的.xml文件,它必需放到類路徑(classPath)的根目錄, Web應(yīng)用一般放在classes目錄中,它需要遵守DTD的規(guī)范(現(xiàn)在是xwork-1.0.dtd)。這個(gè)文件定義了我們的Action,Interceptor,Result的配置和相互之間的映射。下面我們看看用戶注冊(cè)的完整XWork配置文件:

<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www./xwork/xwork-1.0.dtd">

 

<xwork>

 

    <include file="webwork-default.xml"/>

   

    <package name="example" extends="webwork-default">

       <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>

      

       <action name="registersupport" class="example.register.RegisterActionSupport" >

           <result name="success" type="dispatcher">

              <param name="location">/register-result.jsp</param>

           </result>

           <result name="input" type="dispatcher">

              <param name="location">/registerSupport.jsp</param>

           </result>

           <interceptor-ref name="validationWorkflowStack"/>

       </action>

      

    </package>

 

</xwork>

xwork.xml文件的標(biāo)簽元素

Xworkxwork配置文件的所有內(nèi)容,都是定義在<xwork>標(biāo)簽中,它的直接子標(biāo)簽有<package><include>。

Package我們的Action,Interceptor,Result都是在此標(biāo)簽中定義。<package>標(biāo)簽有一個(gè)必需的屬性“name”,它用來標(biāo)識(shí)唯一的一個(gè)package。屬性“extends”是可選的,它用來繼承前面定義的一個(gè)或一個(gè)以上package配置信息,包括所有的interceptor、interceptor-stackaction的配置信息。注意,配置文件按文檔的順序,由上向下執(zhí)行,因此,用“extends”引用的package必需在引用之前定義。屬性“sbstract”是可選的,它用來設(shè)置package為抽象的package,它可以被繼承同時(shí)它的Action配置信息在運(yùn)行時(shí)將不可見。

屬性namespace也是可選的,它用來分隔不同package定義的action,讓這些action處于不同的命名空間(namespaces)。這樣,我們不同的package可以有相同的action命名,因?yàn)榭梢酝ㄟ^命名空間來區(qū)分。如果不指定namespace,默認(rèn)的是空字符串。命名空間也可以被用在安全控制方面,它可以根據(jù)不同的命名空間指定不同的訪問權(quán)限。

是否必需

  

name

用來標(biāo)識(shí)package的名稱

extends

繼承它所擴(kuò)展的package配置信息

namespace

指定package的命名空間,默認(rèn)是””

abstract

聲明package是抽象的

 

Result-type用來定義輸出結(jié)果類型的Class,它用簡單的名-值對(duì)來定義。當(dāng)然,我們自己寫的輸出結(jié)果類型也必需在這里定義。例如:

<result-type name="dispatcher" class="com.opensymphony.webwork.dispatcher.ServletDispatcherResult" default="true"/>,default="true"表示如果在Actionresult中不指定result-type,就使用這個(gè)默認(rèn)的result-type

 

Interceptors它是一個(gè)簡單的<interceptors>  <interceptors/>標(biāo)簽,我們的interceptorinterceptor-stack都在此標(biāo)簽內(nèi)定義。

 

Interceptor當(dāng)然,就是用來定義我們的攔截器。它的定義非常簡單,名-值對(duì)的形式。例如:<interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>。在action中,可以通過<interceptor-ref />來直接引用前面定義了的攔截器。

 

Interceptor-stack用來將上面定義的interceptor組織成堆棧的形式,這樣我們就可以創(chuàng)建一組標(biāo)準(zhǔn)的interceptor,讓它按照順序執(zhí)行。在我們的Action中直接引用這個(gè)interceptor堆棧就可以了,不用逐個(gè)interceptor去引用。

例如:

<interceptor-stack name="validationWorkflowStack">

               <interceptor-ref name="defaultStack"/>

                <interceptor-ref name="validation"/>

                <interceptor-ref name="workflow"/>

            </interceptor-stack>

Interceptor Param:我們的interceptor是在ActionConfig級(jí)別被實(shí)例化和存儲(chǔ)的,也就是說一個(gè)Action引用的每個(gè)interceptor都會(huì)有相應(yīng)的實(shí)例。這樣,我們?cè)诙x和引用interceptor的時(shí)候都可以為它設(shè)置相應(yīng)的參數(shù)值。例如:

<interceptor name="test" class="com.opensymphony.xwork.TestInterceptor">

    <param name="foo">expectedFoo</param>

</interceptor>

ActionInterceptor-stack中引用時(shí)也可以設(shè)置參數(shù),例如:

<interceptor-ref name="test">

    <param name="expectedFoo">expectedFoo</param>

</interceptor-ref>

注意:在Action引用的時(shí)候,如果引用的是Interceptor-stack,則不允許設(shè)置參數(shù),否則會(huì)報(bào)錯(cuò)。

 

Global-results它允許我們定義全局的輸出結(jié)果(global result),比如登陸頁面、操作錯(cuò)誤處理頁面。只要繼承它所在的package,這些輸出結(jié)果都是可見的。

例如:

<global-results>

           <result name="login" type="dispatcher">

              <param name="location">/login.jsp</param>

           </result>

           <result name="error" type="dispatcher">

              <param name="location">/error.jsp</param>

           </result>

       </global-results>

如果我們的Action執(zhí)行完返回“login”,它將調(diào)用上面的這個(gè)輸出結(jié)果,將輸出派遣到根目錄下的login.jsp頁面。

 

Action用來配置Action的名稱(name)和它對(duì)應(yīng)的Class。我們將通過這個(gè)Action的名稱和它所在packagenamespace去配置文件中取得這個(gè)Action的配置信息。它可以通過<param>來設(shè)置參數(shù),Action在執(zhí)行的時(shí)候會(huì)取得配置文件里設(shè)置的參數(shù)(通過攔截器StaticParametersInterceptor)。

Action可以配置一個(gè)或多個(gè)輸出結(jié)果(result)。一個(gè)輸出結(jié)果的名稱,對(duì)應(yīng)于Action執(zhí)行完成返回的字符串。<result>標(biāo)簽的type屬性,對(duì)應(yīng)我們前面定義過的result-type,說明reslut的類型。例如:

<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>

當(dāng)然,我們的Action用到的攔截器也是在這里配置的,通過<interceptor-ref>標(biāo)簽,屬性“name”的值,對(duì)應(yīng)前面定義的interceptorinterceptor-stack如果Action中沒有用<interceptor-ref>標(biāo)簽指定攔截器,它將使用默認(rèn)的<default-interceptor-ref>標(biāo)簽定義的攔截器。

 

Includexwork..xml文件可以被分成好幾個(gè)不同的文件,xwork..xml通過<include>標(biāo)簽引用被包含的文件,例如:<include file="webwork-default.xml"/>。被包含的文件必需是package標(biāo)簽里的內(nèi)容,我們看看<include>標(biāo)簽在配置文件里的位置就知道了。如果要繼承被包含文件的package,我們必需將<include>標(biāo)簽放在其上面,因?yàn)榕渲梦募前凑沼缮隙碌捻樞蚪馕龅摹?/span>


 

實(shí)戰(zhàn)G-Roller-WW

G-Roller-WW介紹

JSTLWebWork的整合

中文解決方案

 

WebWork與其它開源項(xiàng)目的集成

Spring

Hibernate

Xml-RPC


 

總結(jié)

WebWork功能非常強(qiáng)大,除了上面介紹的以外,它還有很好的國際化支持功能,IoC(Inversion of control,依賴倒裝控制)框架支持;同時(shí),它也可以很好的與其它的開源項(xiàng)目集成,如:Sitemesh、Spring、PicoHibernate、JUnit、Quartz等。

 “最好的文檔就是代碼”,WebWork代碼可讀性非常好,特別是2.1版本加了很多詳盡的注釋,在此向讀者強(qiáng)烈推薦,如果想更深入了解WebWork,建議多看它的代碼文檔。

到此,您已經(jīng)了解了WebWork的所有特性。它確實(shí)是一個(gè)非常優(yōu)秀的開源J2EE Web框架,同時(shí)我并不否定其它的框架,比如Struts,TapestryMaverick等,既然存在,它就一定有著自身存在價(jià)值和理由。

這么多的Web框架,有很多朋友在面臨選擇的時(shí)候也許會(huì)非常矛盾,不知應(yīng)該如何抉擇。在這,我的建議:關(guān)于開源Web框架的選擇,應(yīng)該根據(jù)團(tuán)隊(duì)的整體技術(shù)能力和要實(shí)施的項(xiàng)目來共同決定。關(guān)于是否要在項(xiàng)目中使用WebWork,假如你們已經(jīng)在團(tuán)隊(duì)中使用類似Struts這樣的J2EE框架,開發(fā)人員都已熟悉并有了很多技術(shù)和項(xiàng)目經(jīng)驗(yàn)的積累,那我建議你們暫時(shí)不要去使用WebWork,但我強(qiáng)烈建議找一個(gè)有代表性的模塊,將他們嘗試用WebWork改寫,我想,下個(gè)項(xiàng)目,也許你們就會(huì)改變注意,考慮使用WebWork。但,如果你們正在為具體選擇哪種Web框架而發(fā)愁,我相信WebWork一定是您最佳的選擇。

WebWork功能很多,但我們要牢記它的宗旨:致力于組件化和代碼重用,同時(shí)簡單、靈活,更好的提高生產(chǎn)率。

                                                 

附錄

我鐘愛的Opensympnony

我是從WebWork開始認(rèn)識(shí)Opensymphonyhttp://www.)的,它是一個(gè)很好提供開源項(xiàng)目的組織。同Jakarta相比,這里的組件(Component)更多的是精致小巧的設(shè)計(jì),它們尤以簡單易用和可插拔的靈活性見長。除了我們這里介紹的WebWorkXwork,下面我們將簡單介紹其他的一些組件:

 

OSWorkFlow工作流引擎。它的流程定義靈活清晰,工作流引擎支持多種持久方式(MemoryStore ,SerializableStore, JDBCStore, OfbizStore, and EJBStore,HibernateStore等),具有極強(qiáng)的可擴(kuò)展性。它提供了強(qiáng)大的腳本支持(BeanShell、BSF等),多樣化的function,function可以直接使用普通java類函數(shù)、XworkAction、JMS、EJB、腳本等。它還提供了一個(gè)基于JGraph的流程設(shè)計(jì)器。

   最新版本OSWorkFlow2.7也添加了對(duì)Spring框架的支持,流程設(shè)計(jì)器也有了很好的改進(jìn)。

 

Quartz它是一個(gè)實(shí)現(xiàn)任務(wù)定時(shí)調(diào)度的框架,原先是一個(gè)獨(dú)立的project,后來并入OpenSymphony。它是一個(gè)非常輕量級(jí)的,并具有高度的可升級(jí)性,提供了簡單易用的接口。它提供了強(qiáng)大的任務(wù)調(diào)度運(yùn)行方式,可以獨(dú)立運(yùn)行、可以作為EJB部署于容器中、本身支持cluster,等等。

  最新的版本是1.4,在性能和功能上都又有了很好的提高。

 

SiteMesh它主要用來對(duì)Web頁面的布局管理,并且致力為很多頁面組成的大型網(wǎng)站提供提供統(tǒng)一的風(fēng)格、導(dǎo)航和布局功能。

它通過filter截取requestresponse,并給原始的頁面加入一定的裝飾(Decorator(可能為header,footer...),然后把結(jié)果返回給客戶端,并且被裝飾的原始頁面并不知道SiteMesh的裝飾,這也就達(dá)到了解耦的目的。

 

OSCacheJ2EE Caching機(jī)制。它主要用于JSP CachingRequest Caching、General-Purpose Cache三個(gè)方面。在JSP CachingRequest Caching方面,OSCache能夠解決動(dòng)態(tài)網(wǎng)站的基本問題:緩存動(dòng)態(tài)內(nèi)容、緩存二進(jìn)制內(nèi)容、錯(cuò)誤包容。在General-Purpose Cache方面,在Java應(yīng)用中通過調(diào)用OSCacheAPI來緩存任意的Java對(duì)象,hibernate 2.0開始對(duì)其也有支持。

OSCache標(biāo)記庫是一種開創(chuàng)性的JSP定制標(biāo)記應(yīng)用,提供了在現(xiàn)有JSP頁面之內(nèi)實(shí)現(xiàn)快速內(nèi)存緩沖的功能。雖然已經(jīng)有一些供應(yīng)商在提供各種形式的緩存產(chǎn)品,但是,它們都屬于面向特定供應(yīng)商的產(chǎn)品。OSCache能夠在任何JSP 1.2兼容的服務(wù)器上運(yùn)行,它不僅能夠?yàn)樗杏脩艟彌_現(xiàn)有JSP代碼塊,而且能夠以用戶為單位進(jìn)行緩沖。OSCache還包含一些提高可伸縮性的高級(jí)特性,比如:緩沖到磁盤,可編程的緩沖刷新,異常控制,等等。

 

OSCore是一組公共工具類,提供了豐富的常用方法的標(biāo)準(zhǔn)實(shí)現(xiàn),供其他OpenSymphony組件使用。

 

PropertySet管理屬性(Property)的好工具,它提供一個(gè)抽象方法來向一個(gè)持久性存儲(chǔ)源中動(dòng)態(tài)保存和取回類型化的屬性數(shù)據(jù)。支持多種持久化方式,例如:XML, EJB, Ofbiz, JDBC, Castor JDO,Memory等,同時(shí)也提供了一個(gè)簡單的API來根據(jù)你的需要寫你自己定制的PropertySets。

 

Clickstream它是一個(gè)JavaServlet過濾器,用來跟蹤用戶請(qǐng)求(比如:點(diǎn)擊)和請(qǐng)求隊(duì)列(比如:點(diǎn)擊流)以向網(wǎng)絡(luò)管理員顯示誰在她的網(wǎng)站上以及每個(gè)用戶正在訪問那個(gè)頁面。


 

從技術(shù)的角度Struts1.1WebWork2的比較

Struts1.1

WebWork2

Action

Struts里面,每一個(gè)Action類必需要繼承一個(gè)抽象的類org.apache.struts.action.Action。這個(gè)在Java編程中會(huì)引來一些問題,就是關(guān)于多種繼承的問題。

WebWorkAction類僅需要實(shí)現(xiàn)接口com.opensymphony.xwork.Action,也可以實(shí)現(xiàn)其它的接口來實(shí)現(xiàn)更多的功能,譬如:validate(驗(yàn)證),localware(國際化)等。當(dāng)然,它也提供了一個(gè)類ActionSupport集成了上面的所有功能,我們?cè)陂_發(fā)中可以根據(jù)需要選擇。

線程模型

Struts Action必需是threadsafe方式,它僅僅允許一個(gè)實(shí)例去處理所有的請(qǐng)求。所以action用到的所有的資源都必需統(tǒng)一同步,這個(gè)就引起了線程安全的問題。

WebWork中,每個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)Action,因此沒有線程的安全問題。實(shí)際上Servlet容器對(duì)每個(gè)請(qǐng)求也產(chǎn)生多個(gè)對(duì)象,它也沒有證明對(duì)性能和垃圾回收產(chǎn)生太多的影響。

Servlet的依賴

Struts處理Action時(shí)必需要依賴ServletRequest ServletResponse,所有它擺脫不了Servlet容器。

WebWorkAction不用依賴Web層和其它的容器。它可以通過ActionContext,直接去訪問RequestResponse,但這個(gè)是可選的,只有在必需的請(qǐng)求下使用。

測(cè)試

Struts的每個(gè)Action都同Web層耦合在一起,這樣它的測(cè)試依賴于Web容器,單元測(cè)試也很難實(shí)現(xiàn)。不過有一個(gè)Junit的擴(kuò)展工具Struts TestCase可以實(shí)現(xiàn)它的單元測(cè)試。

Webworkaction能夠通過賦予一定的屬性,就可以執(zhí)行單元測(cè)試。同時(shí)也可以使用一個(gè)mock的實(shí)例去測(cè)試,而不是通過啟動(dòng)web容器來進(jìn)行測(cè)試。

FormBean

Struts要求有FormBean對(duì)應(yīng)每一個(gè)表單,而且FormBean必需繼承抽象類ActionForm。而使用DynaBeans實(shí)際上沒有太大的意義。不能夠很好的處理現(xiàn)有的模型。

Webwork 能夠動(dòng)態(tài)的收集web的數(shù)據(jù)然后再賦值給bean。它也可以使用FormBean的形式,FormBean可以是普通的DTO和域?qū)ο?,它不用重新根?jù)域?qū)ο髞砩尚碌?/span>FormBean,也不需繼承抽象類ActionForm

前端表達(dá)式語言

Struts集成了JSTL,所以它主要使用JSTL的表達(dá)式語言來獲取數(shù)據(jù)??墒?/span>JSTL的表達(dá)式語言在Collection和索引屬性方面處理顯得很弱。

WebWork的表達(dá)式語言使用了功能強(qiáng)大的OGNL。它使用OGNL建立一個(gè)OgnlValueStack來搜索數(shù)據(jù)。Webwork前端也可以使用JSTL,但它同時(shí)支持:velocity、freemaker、jspparer、xml。

類型的轉(zhuǎn)換

StrutsFormBean把所有的數(shù)據(jù)都作為String類型,它可以使用工具Commons-Beanutils進(jìn)行類型轉(zhuǎn)化。但它的轉(zhuǎn)化都是在Class級(jí)別,而且轉(zhuǎn)化的類型是不可配置的。類型轉(zhuǎn)化時(shí)的錯(cuò)誤信息返回給用戶也是非常困難的。

WebWork使用OGNL進(jìn)行類型轉(zhuǎn)化,提供了所有基本類型的轉(zhuǎn)化功能。類型轉(zhuǎn)化可以直接對(duì)一個(gè)Class進(jìn)行(Class級(jí)別)轉(zhuǎn)化,也可以對(duì)Class的字段進(jìn)行類型轉(zhuǎn)化。它使用攔截器可以很容易的將類型轉(zhuǎn)化的錯(cuò)誤信息返回給用戶,而且錯(cuò)誤信息可以對(duì)應(yīng)到一個(gè)相應(yīng)的字段。

對(duì)Action 執(zhí)行前和后的處理

Struts處理Action的時(shí)候是基于classhierarchies,很難在action處理前和后進(jìn)行操作。

Webwork2 允許您處理Action可以通過攔截器,就是在每一個(gè)Action處理前或者后進(jìn)行其它操作。它的攔截器可以在配置文件中動(dòng)態(tài)添加,這樣Action和攔截器之間完全解藕,更好的實(shí)現(xiàn)了組件化。

驗(yàn)證處理

Struts的驗(yàn)證是調(diào)用FormBeanvalidator()方法,其實(shí)就是對(duì)FormBean的驗(yàn)證。它一般使用框架Commons Validation進(jìn)行數(shù)據(jù)驗(yàn)證處理。它使用了一個(gè)全局的配置文件validation.xml定義了FormBean的驗(yàn)證信息。StrutsFormBean屬性都被認(rèn)為是String類型,所以它在驗(yàn)證時(shí)也需要額外的類型轉(zhuǎn)化。

WebWork使用Xwork的驗(yàn)證框架進(jìn)行驗(yàn)證處理,它可以通過配置攔截器來激活。它可以為每個(gè)需要驗(yàn)證的Class指定一個(gè)xml驗(yàn)證文件,也可以為一個(gè)Class在不同的情況指定不同的xml驗(yàn)證文件。WebWork證可以給每個(gè)Action類指定對(duì)應(yīng)的驗(yàn)證文件,也可以給Action的字段去指定驗(yàn)證文件。通過攔截器來組裝Action和其驗(yàn)證文件,使它們之間完全解藕。

對(duì)Action執(zhí)行的控制

Struts創(chuàng)建一個(gè)Action,如果想控制它的執(zhí)行順序?qū)?huì)非常困難。甚至你要重新去寫Servlet來實(shí)現(xiàn)你的這個(gè)功能需求。

在這個(gè)方面,WebWork的攔截器棧提供了強(qiáng)大的功能。Action的所有切面功能都有攔截器來實(shí)現(xiàn)(比如:取得request請(qǐng)求參數(shù)、驗(yàn)證處理等),這樣你就可以用攔截器棧來組織攔截器的執(zhí)行順序。例如:你需要在使用request請(qǐng)求參數(shù)來設(shè)置Action屬性之前,使用IoC框架設(shè)置Action的屬性,反之已然。這時(shí),你就可以為packageAction指定一個(gè)攔截器棧來實(shí)現(xiàn)。

 


 

WebWork的項(xiàng)目資源

下面是我在研究WebWork時(shí),使用的資源和研究過的項(xiàng)目,希望能對(duì)你能有幫助。

1、 當(dāng)然就是WebWork的官方網(wǎng)站:http://www./webwork/

里面有最新的WebWork文檔和它的一個(gè)wiki

2、 一本好書:Java Open Source Programming : with XDoclet, JUnit, WebWork, Hibernate,里面有很好的WebWork教程。它附帶的源代碼可以去http://www.amazon.com/下載,里面的petsoar是一個(gè)非常好的WebWork開源項(xiàng)目。

3、 Confluencehttp://www./software/confluence)是專業(yè)的J2EE wiki,用于知識(shí)管理和項(xiàng)目組交流。它使用的架構(gòu)是webwork2+Spring+Hibernate。Confluence雖是商業(yè)軟件,不過對(duì)于 OpenSource的項(xiàng)目它全部免費(fèi)提供。它的架構(gòu)思想很值得我們?nèi)W(xué)習(xí)。

4、 OpenReports(http://www.)是一個(gè)開源的項(xiàng)目,基于Web的報(bào)表系統(tǒng)。它用到的技術(shù)有:WebWork 2.0、Velocity Hibernate。

參考資料

http://www./

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

注意:<result name="success" type="dispatcher">

              <param name="location">register-result.jsp</param>

       </result>

/register-result.jsp

 

location可以是一個(gè)絕對(duì)的URL,如http://www./也可以使用相對(duì)的URL。如果location以“/”開頭,則容器認(rèn)為相對(duì)于當(dāng)前Web應(yīng)用的根,否則,容器將解析為相對(duì)于當(dāng)前請(qǐng)求的URL。這種重定向結(jié)果,將導(dǎo)致客戶端瀏覽器的請(qǐng)求URL跳轉(zhuǎn)。從瀏覽器中的地址欄中可以看到新的URL地址。

 

location可以是一個(gè)絕對(duì)的URL,如response.sendRedirect("http://java.")也可以使用相對(duì)的URL。

如果location以“/”開頭,則容器認(rèn)為相對(duì)于當(dāng)前Web應(yīng)用的根,否則,容器將解析為相對(duì)于當(dāng)前請(qǐng)求的URL。

這種重定向的方法,將導(dǎo)致客戶端瀏覽器的請(qǐng)求URL跳轉(zhuǎn)。從瀏覽器中的地址欄中可以看到新的URL地址,

作用類似于上面設(shè)置HTTP響應(yīng)頭信息的實(shí)現(xiàn)。

 

在客戶端瀏覽器地址欄中不會(huì)顯示出轉(zhuǎn)向后的地址

 

RequestDispatcher是一個(gè)Web資源的包裝器,可以用來把當(dāng)前request傳遞到該資源,

或者把新的資源包括到當(dāng)前響應(yīng)中。

forward()方法將當(dāng)前的requestresponse重定向到該RequestDispacher指定的資源。

include()方法將把Request Dispatcher資源的輸出包含到當(dāng)前輸出中。

 

RequestDispatcher.forward()方法和HttpServletResponse.sendRedirect()方法的區(qū)別是:

前者僅是容器中控制權(quán)的轉(zhuǎn)向,在客戶端瀏覽器地址欄中不會(huì)顯示出轉(zhuǎn)向后的地址;

后者則是完全的跳轉(zhuǎn),瀏覽器將會(huì)得到跳轉(zhuǎn)的地址,并重新發(fā)送請(qǐng)求鏈接。

這樣,從瀏覽器的地址欄中可以看到跳轉(zhuǎn)后的鏈接地址。

 

注意:所有代碼程序的重新檢查。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多