webber

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            11 Posts :: 2 Stories :: 3 Comments :: 0 Trackbacks

          webwork2.0配置詳解

          首先下載WebWork2 的最新版本(http://www.opensymphony.com/webwork/)。

          這里我們所談及的WebWork,實際上是Webwork+XWork的總集,Webwork1.x 版本中,
          整個框架采用了緊耦合的設計(類似Struts),而2.0 之后,Webwork被拆分為兩個部分,
          即Webwork 2.x +XWork 1.x,設計上的改良帶來了系統靈活性上的極大提升。

          本例的部署如下圖所示

          webwork能為我們做什么:
          1.將Web頁面中的輸入元素封裝為一個(請求)數據對象。
          2.根據請求的不同,調度相應的邏輯處理單元,并將(請求)數據對象作為參數傳入。
          3.邏輯處理單元完成運算后,返回一個結果數據對象。
          4.將結果數據對象中的數據與預先設計的表現層相融合并展現給用戶。
          首先來看登錄界面:
          index.jsp
          <html>
          <body>
          <form action="/login.action">
          <p align="center">
          登錄<br> </p>
          用戶名:<input type="text" name="model.username" /><br>
          密 碼 :<input type="password" name="model.password" /><br>
          <p align="center"><input type="submit" value="提交" name="B1"/><input type="reset" value="重置" name="B2"/></p>
          </form>
          </body>
          </html>
           這里的index.jsp實際上是由純html 組成,非常簡單,其中包含一個表單:
          <form action="/login.action">
          這表明其提交對象為/login.action . 表單中同時包含兩個文本輸入框,
          <input type="text" name="model.username" />
          <input type="password" name="model.password" />
          可以看到,兩個輸入框的名稱均以“model”開頭,這是因為在這里我們采用了WebWork
          中Model-Driven的Action驅動模式
          當表單被提交之時,瀏覽器會以兩個文本框的值作為參數,向Web 請求以/login.action命名的服務。
          標準HTTP協議中并沒有.action結尾的服務資源。我們需要在web.xml中加以設定:
          ……
          <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結尾的服務請求將由ServletDispatcher 接管。
          ServletDispatcher 接受到Servlet Container 傳遞過來的請求,將進行一下幾個動作:
          1. 從請求的服務名(/login.action)中解析出對應的Action名稱(login)
          2. 遍歷 HttpServletRequest、HttpSession、ServletContext 中的數據,并將其復制到
          Webwork的Map實現中,至此之后,所有數據操作均在此Map結構中進行,從而將內部結構與Servlet API相分離。
          至此,Webwork 的工作階段結束,數據將傳遞給XWork 進行下一步處理。從這里也可以看
          到Webwork和xwork之間的切分點,Webwork為xwork提供了一個面向Servlet 的協議轉換
          器,將Servlet 相關的數據轉構轉換成xwork所需要的通用數據格式,而xwork將完成實際的
          服務調度和功能實現。
          這樣一來,以xwork為核心,只需替換外圍的協議轉換組件,即可實現不同技術平臺之間的
          切換(如將面向Servlet的Webwork替換為面向JMS的協議轉換器實現,即可在保留應用邏
          輯實現的情況下,實現不同外部技術平臺之間的移植)。
          3. 以上述信息作為參數,調用ActionProxyFactory創建對應的ActionProxy實例。
          ActionProxyFactory 將根據Xwork 配置文件(xwork.xml)中的設定,創建
          ActionProxy實例,ActionProxy中包含了Action的配置信息(包括Action名稱,
          對應實現類等等)。
          4. ActionProxy創建對應的Action實例,并根據配置進行一系列的處理程序。包括
          執行相應的預處理程序(如通過Interceptor 將Map 中的請求數據轉換為Action
          所需要的Java 輸入數據對象等),以及對Action 運行結果進行后處理。
          ActionInvocation 是這一過程的調度者。而com.opensymphony.xwork.
          DefaultActionInvocation 則是XWork 中對ActionInvocation 接口的標準實現,如
          果有精力可以對此類進行仔細研讀,掌握了這里面的玄機,相信XWork的引擎
          就不再神秘。

          下面我們來看配置文件:
          xwork.xml:
          <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN"
          "http://www.opensymphony.com/xwork/xwork-1.0.dtd">
          <xwork>
          <include file="webwork-default.xml" />

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

          <action name="login" class="net.xiaxin.webwork.action.LoginAction">
          <result name="success" type="dispatcher">

          <param name="location">/main.jsp</param>
          </result>
          <result name="loginfail" type="dispatcher">

          <param name="location">/index.jsp</param>
          </result>
          <interceptor-ref name="params" />
          <interceptor-ref name="model-driven"/>
          </action>
          </package>
          </xwork>
          ⑴ include
          通過include 節點,我們可以將其他配置文件導入到默認配置文件xwork.xml 中。
          從而實現良好的配置劃分。
          這里我們導入了Webwork 提供的默認配置webwork-default.xml(位于
          webwork.jar 的根路徑)。
          ⑵ package
          XWork中,可以通過package對action進行分組。類似Java 中package和class的
          關系。為可能出現的同名Action提供了命名空間上的隔離。
          同時,package還支持繼承關系。在這里的定義中,我們可以看到:
          extends="webwork-default"
          "webwork-default"是webwork-default.xml文件中定義的package,這里通
          過繼承,"default" package 自動擁有"webwork-default" package 中的所有
          定義關系。
          這個特性為我們的配置帶來了極大便利。在實際開發過程中,我們可以根據自身
          的應用特點,定義相應的package模板,并在各個項目中加以重用,無需再在重復
          繁瑣的配置過程中消耗精力和時間。
          此外,我們還可以在Package節點中指定namespace,將我們的action分為若干個
          邏輯區間。如:
          <package name="default" namespace="/user"
          extends="webwork-default">
          就將此package中的action定義劃歸為/user 區間,之后在頁面調用action的時候,
          我們需要用/user/login.action 作為form action 的屬性值。其中的/user/就指定了此
          action的namespace,通過這樣的機制,我們可以將系統內的action進行邏輯分類,
          從而使得各模塊之間的劃分更加清晰。
          ⑶ action
          Action配置節點,這里可以設定Action的名稱和對應實現類。
          ⑷ result
          通過result 節點,可以定義Action 返回語義,即根據返回值,決定處理模式以及
          響應界面。
          這里,返回值"success"(Action 調用返回值為String 類型)對應的處理模式為
          "dispatcher"。
          可選的處理模式還有:
          1. dispatcher
          本系統頁面間轉向。類似forward。
          2. redirect
          瀏覽器跳轉。可轉向其他系統頁面。
          3. chain
          將處理結果轉交給另外一個Action處理,以實現Action的鏈式處理。
          4. velocity
          將指定的velocity模板作為結果呈現界面。
          5. xslt
          將指定的XSLT 作為結果呈現界面。
          隨后的param節點則設定了相匹配的資源名稱。
          ⑷ interceptor-ref
          設定了施加于此Action的攔截器(interceptor)。關于攔截器,請參見稍后的“XWork
          攔截器體系”部分。
          interceptor-ref定義的是一個攔截器的應用,具體的攔截器設定,實際上是繼
          承于webwork-default package,我們可以在webwork-default.xml 中找到
          對應的"params"和"model-driven"攔截器設置:
          <interceptors>
          ……
          <interceptor name="params"
          class="com.opensymphony.xwork.interceptor.ParametersInt
          erceptor" />
          <interceptor name="model-driven"
          class="com.opensymphony.xwork.interceptor.ModelDrivenIn
          terceptor" />
          ……
          </interceptors>
          "params"大概是Webwork 中最重要、也最常用的一個Interceptor。上面曾經將
          MVC工作流程劃分為幾個步驟,其中的第一步:
          “將 Web 頁面中的輸入元素封裝為一個(請求)數據對象”
          就是通過"params"攔截器完成。Interceptor 將在Action 之前被調用,因而,
          Interceptor 也成為將Webwork傳來的MAP 格式的數據轉換為強類型Java 對象的

          最佳實現場所。
          "model-driven"則是針對Action 的Model驅動模式的interceptor 實現。具體描
          述請參見稍后的“Action驅動模式”部分
          很可能我們的Action 都需要對這兩個interceptor 進行引用。我們可以定義一個
          interceptor-stack,將其作為一個interceptor 組合在所有Action 中引用。如,上面
          的配置文件可修改為:
          <xwork>
          <include file="webwork-default.xml" />
          <package name="default" extends="webwork-default">
          <interceptors>
          <interceptor-stack name="modelParamsStack">
          <interceptor-ref name="params" />
          <interceptor-ref name="model-driven" />
          </interceptor-stack>
          </interceptors>
          <action name="login"
          class="net.xiaxin.webwork.action.LoginAction">
          <result name="success" type="dispatcher">
          <param name="location">/main.jsp</param>
          </result>
          <result name="loginfail" type="dispatcher">
          <param name="location">/index.jsp</param>
          </result>
          <interceptor-ref name="modelParamsStack" />
          </action>
          </package>
          </xwork>
          通過引入interceptor-stack,我們可以減少interceptor 的重復申明。
          下面是我們的Model對象:
          LoginInfo.java:
          public class LoginInfo {
          private String password;
          private String username;
          private List messages = new ArrayList();
          private String errorMessage;

          public List getMessages() {
          return messages;
          }
          public String getErrorMessage() {
          return errorMessage;
          }
          public void setErrorMessage(String errorMessage) {
          this.errorMessage = errorMessage;
          }
          public String getPassword() {
          return password;
          }
          public void setPassword(String password) {
          this.password = password;
          }
          public String getUsername() {
          return username;
          }
          public void setUsername(String username) {
          this.username = username;
          }
          }
          很簡單,這只是一個純粹的值對象(Value-Object)。這里,它扮演著模型(Model)的
          角色,并與Action的輸入輸出密切相關。
          與 SpringMVC中的Command對象不同,Webwork 中的Model對象,扮演著承上啟下
          的角色,它既是Action的輸入參數,又包含了Action處理的結果數據。
          換句話說,輸入的Http請求參數,將被存儲在Model對象傳遞給Action進行處理,Action
          處理完畢之后,也將結果數據放置到Model 對象中,之后,Model 對象與返回界面融合生
          成最后的反饋頁面。
          也正由于此,筆者建議在實際開發中采用Model-Driven 模式,而非Property-Driven 模
          式(見稍后“Action驅動模式”部分),這將使得業務邏輯更加清晰可讀。
          對應的Action代碼
          public class LoginAction implements Action, ModelDriven {
          private final static String LOGIN_FAIL="loginfail";
          LoginInfo loginInfo = new LoginInfo();
          public String execute() throws Exception {
          if ("erica".equalsIgnoreCase(loginInfo.getUsername())
          && "mypass".equals(loginInfo.getPassword())) {
          //將當前登錄的用戶名保存到Session
          ActionContext ctx = ActionContext.getContext();
          Map session = ctx.getSession();
          session.put("username",loginInfo.getUsername());
          //出于演示目的,通過硬編碼增加通知消息以供顯示
          loginInfo.getMessages().add("message1");
          loginInfo.getMessages().add("message2");
          loginInfo.getMessages().add("message3");
          return SUCCESS;
          }else{
          loginInfo.setErrorMessage("Username/Password Error!");
          return LOGIN_FAIL;
          }
          }
          public Object getModel() {
          return loginInfo;
          }
          }

           

           LoginAction實現了兩個接口:
          1. Action
          Action接口非常簡單,它指定了Action的入口方法(execute),并定義了
          幾個默認的返回值常量:
          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;
          }

          SUCCESS、NONE、ERROR、INPUT、LOGIN 幾個字符串常量定義了常用的
          幾類返回值。我們可以在Action 實現中定義自己的返回類型,如本例中的
          LOGIN_FAIL定義。
          而execute方法,則是Action的入口方法,XWork將調用每個Action的execute
          方法以完成業務邏輯處理。
          2. ModelDriven
          ModelDriven接口更為簡潔:
          public interface ModelDriven {
          Object getModel();
          }
          ModelDriven僅僅定義了一個getModel方法。XWork在調度Action時,將通
          過此方法獲取Model 對象實例,并根據請求參數為其設定屬性值。而此后的
          頁面返回過程中,XWork 也將調用此方法獲取Model 對象實例并將其與設定
          的返回界面相融合。
          注意這里與Spring MVC 不同,Spring MVC 會自動為邏輯處理單元創建
          Command Class實例,但Webwork不會自動為Action創建Model對象實例,
          Model 對象實例的創建需要我們在Action 代碼中完成(如LoginAction 中
          LoginInfo對象實例的創建)。
          另外,如代碼注釋中所描述,登錄成功之后,我們隨即將username保存在Session之中,
          這也是大多數登錄操作必不可少的一個操作過程。
          這里面牽涉到了Webwork中的一個重要組成部分:ActionContext。
          ActionContext為Action提供了與容器交互的途徑。對于Web 應用而言,與容器的交互
          大多集中在Session、Parameter,通過ActionContext我們在代碼中實現與Servlet API無關的
          容器交互。
          如上面代碼中的:
          ActionContext ctx = ActionContext.getContext();
          Map session = ctx.getSession();
          session.put("username",loginInfo.getUsername());
          同樣,我們也可以操作Parameter:
          ActionContext ctx = ActionContext.getContext();
          Map params = ctx.getParameters();
          String username = ctx.getParameters("username");
          上述的操作,將由XWork根據當前環境,調用容器相關的訪問組件(Web 應用對應的
          就是Webwork)完成。上面的ActionContext.getSession(),XWork 實際上將通過Webwork
          提供的容器訪問代碼“HttpServletRequest.getSession()”完成。
          注意到,ActionContext.getSession返回的是一個Map類型的數據對象,而非HttpSession。
          這是由于WebWork對HttpSession進行了轉換,使其轉變為與Servlet API無關的Map對象。
          通過這樣的方式,保證了Xwork 所面向的是一個通用的開放結構。從而使得邏輯層與表現
          層無關。增加了代碼重用的可能。
          此 外, 為了提供與Web 容器直接交互的可能。WebWork 還提供了一個
          ServletActionContext實現。它擴展了ActionContext,提供了直接面向Servlet API的容器訪
          問機制。
          我們可以直接通過ServletActionContext.getRequest 得到當前HttpServletRequest 對象的
          引用,從而直接與Web 容器交互。
          獲得如此靈活性的代價就是,我們的代碼從此與ServletAPI 緊密耦合,之后系統在不
          同平臺之間移植就將面臨更多的挑戰(同時單元測試也難于進行)。
          平臺移植的需求并不是每個應用都具備。大部分系統在設計階段就已經確定其運行平
          臺,且無太多變更的可能。不過,如果條件允許,盡量通過ActionContext 與容器交互,而
          不是平臺相關的ServletActionContext,這樣在順利實現功能的同時,也獲得了平臺遷移上
          的潛在優勢,何樂而不為。
          登錄成功界面:
          main.jsp:
          <%@ taglib prefix="ww" uri="webwork"%>
          <html>
          <body>
          <p align="center">Login Success!</p>
          <p align="center">Welcome!
          <ww:property value="#session['username']"/>
          </p>
          <p align="center">
          <b>Messages:</b><br>
          <ww:iterator value="messages" status="index">
          <ww:if test="#index.odd == true">
          !<ww:property/><br>
          </ww:if>
          <ww:else>
          *<ww:property/><br>
          </ww:else>
          </ww:iterator>
          </p>
          </body>
          </html>
          這里我們引入了Webwork的taglib,如頁面代碼第一行的申明語句。
          下面主要使用了三個tag:
           <ww:property value="#session['username']"/>
          讀取Model對象的屬性填充到當前位置。
          value指定了需要讀取的Model對象的屬性名。
          這里我們引用了LoginAction在session中保存的’username’對象。
          由于對應的Model(LoginInfo)中也保存了username 屬性。下面的語句與之
          效果相同:
          <ww:property value="username"/>
          與 JSP2中的EL類似,對于級聯對象,這里我們也可以通過“.”操作符獲得
          其屬性值,如value="user.username"將得到Model 對象中所引用的user
          對象的username 屬性(假設LoginInfo中包含一個User 對象,并擁有一個名
          為“username”的屬性)。
          關于EL的內容比較簡單,本文就不再單獨開辟章節進行探討。
          Webwork中包括以下幾種特殊的EL表達式:
          parameter[‘username’] 相當于request.getParameter(“username”);
          request[‘username’] 相當于request.getAttribute(“username”);
          session[‘username’] 從session中取出以“username”為key的值
          application[‘username’] 從ServletContext中取出以“username”為key
          的值
          注意需要用“#”操作符引用這些特殊表達式。
          另外對于常量,需要用單引號包圍,如#session['username'] 中的
          'username'。
           <ww:iterator value="messages" status="index">
          迭代器。用于對java.util.Collection、java.util.Iterator、java.util.Enumeration,、
          java.util.Map、Array類型的數據集進行循環處理。
          其中,value屬性的語義與<ww:property>中一致。
          而 status屬性則指定了循環中的索引變量,在循環中,它將自動遞增。
          而在下面的<ww:if>中,我們通過“#”操作符引用這個索引變量的值。
          索引變量提供了以下幾個常用判定方法:
          first 當前是否為首次迭代
          last 當前是否為最后一次迭代
          odd 當前迭代次數是否奇數
          even 當前迭代次數是否偶數
          <ww:if test="#index.odd == true">和<ww:else>
          用于條件判定。
          test屬性指定了判定表達式。表達式中可通過“#”操作符對變量進行引用。
          表達式的編寫語法與java 表達式類似。
          類似的,還有<ww:elseif test="……">。
          登錄失敗界面
          實際上,這個界面即登錄界面index.jsp。只是由于之前出于避免干擾的考慮,隱藏了
          index.jsp中顯示錯誤信息的部分。
          完整的index.jsp如下:
          <%@ page pageEncoding="gb2312"
          contentType="text/html;charset=gb2312"%>
          <%@ taglib prefix="ww" uri="webwork"%>
          <html>
          <body>
          <form action="/login.action">
          <p align="center">
          登錄<br>
          <ww:if test="errorMessage != null">
          <font color="red">
          <ww:property value="errorMessage"/>
          </font>
          </ww:if>
          </p>
          用戶名:
          <input type="text" name="model.username" />
          <br>
          密 碼 :
          <input type="password" name="model.password" />
          <br>
          <p align="center">
          <input type="submit" value="提交" name="B1"/>
          <input type="reset" value="重置" name="B2"/>
          </p>
          </form>
          </body>
          </html>
          這里首先我們進行判斷,如果Model中的errorMessage不為null,則顯示錯誤信息。這
          樣,在用戶第一次登錄時,由于Model對象尚未創建,errorMessage自然為null,錯誤信息
          不會顯示,即得到了與之前的index.jsp同樣的效果。
          posted on 2010-02-10 16:44 webber 閱讀(1583) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 油尖旺区| 凉城县| 肇源县| 广德县| 峡江县| 乐陵市| 石柱| 永和县| 株洲市| 梁河县| 齐齐哈尔市| 麦盖提县| 札达县| 漾濞| 万年县| 正镶白旗| 新乐市| 登封市| 黎城县| 兴城市| 古田县| 长治县| 青龙| 天峨县| 含山县| 保亭| 民权县| 罗城| 铜陵市| 比如县| 南靖县| 高雄市| 柳林县| 修水县| 华容县| 九寨沟县| 宜州市| 平果县| 江津市| 扶风县| 德江县|