Starting Struts2--Core Components(3)

          Posted on 2007-08-09 17:05 puras 閱讀(1317) 評論(3)  編輯  收藏 所屬分類: Struts2.0

          Result Types

          從action生成結(jié)果,并返回組用戶不同的結(jié)果值,不都需要相同的類型.結(jié)果"success"可以渲染為一JSP頁面,但結(jié)果"error"可能需要發(fā)送一個HTTP頭返回給瀏覽器.

          結(jié)果的類型使用"type"屬性在結(jié)果節(jié)點配置.與"name"屬性相似,這個屬性也有一個默認(rèn)值-"dispatcher"-將渲染JSPs.大多數(shù)的時間,你將使用所提供的結(jié)果類型,但有時也可能提供自定義的實現(xiàn).

          Request and Form Data

          為了要做出Action應(yīng)該如何工作的決定,并且提供數(shù)據(jù)的數(shù)據(jù)庫持久對象,Action可能需要從請求字符串中訪問值,并生成數(shù)據(jù).

          Struts2沿序JavaBean的方式-如果你想訪問數(shù)據(jù),你需要為字段提供一個getter和setter方法.訪問請求字符串和form里的值是一樣的.每個請求字符串或是Form里的值都是一個簡單的名值對,所以為一個特定的名稱賦值,需在action里創(chuàng)建一個setter方法.例如,如果JSP發(fā)起了一個請求,"/home.action?framework=struts&version=2",Action需要提供setter方法"setFramework(String frameworkname)",和setter方法"setVersion(int version)".

          注意在這個例子中,setter方法不是一定需要一個String的值.默認(rèn)的,Struts2將從一個String轉(zhuǎn)換成action所需的類型.可以轉(zhuǎn)換所有的原始類型和基礎(chǔ)對象類型,而且可以配置你自己的自定義類.Struts2同樣可以操作復(fù)雜對象中的值,例如,一個名稱在Form元素中稱為"person.address.home.postcode",值為"2",Struts2將使用同樣的調(diào)用方式"getPerson().getAddress().getHome().setPostcode(2)".

          Accessing Business Services

          到現(xiàn)在為止,我們都在討論如果配置action,如果控制渲染不同的結(jié)果返回給用戶.對于action是做什么的,是非常重要的一部分,但是,返回它們的結(jié)果之前,一些處理需要執(zhí)行.對于這個,它們需要訪問一些不同類型的對象-商業(yè)對象,數(shù)據(jù)訪問對象,或是其他資源.

          為了提供一個松耦合的系統(tǒng),Struts2使用稱為依賴注入或是控制反轉(zhuǎn)(IOC)的技術(shù).依賴注入可以通過構(gòu)造函數(shù)注入,接口注入和set方法注入來實現(xiàn).Struts2使用set方法注入.意思是對于action可用的對象,你僅需要提供一個setter.首選的依賴注入框架是Spring框架,可以通過插件配置進(jìn)來.另一個選擇是Plexus,或都如果你喜歡,你可以替換成你自己的實現(xiàn).

          也有一些對象不能用Spring框架管理,比如像HttpServletRequest.這些對象是組合使用setter注入和接口注入來操作.對于每一個非商業(yè)對象,都有個相應(yīng)的口(大家都知道的"aware"接口),Action必須實現(xiàn)這個接口.

          注:
          WebWork最初有自己的依賴注入框架.它在2.2版時,刪除了這個特征,而改用Spring框架替換.最初的組件框架是基于接口的,所以為每個組件接口和接口的實現(xiàn)類,都需要提供.

          另外,每個組件都有一個"Aware"接口,為組件提供一個setter.如果接口是"UserDAO",那么Aware接口則為"UserDAOAware"(約定俗成),并且擁有一個方法-一個setter,"void setUserDAO(UserDAO dao);".

          攔截器會為必要的接口和setters注入必要的對象注入.

          Accessing Data from the Action

          有些時候,需要查看被action修改過的對象.有幾種技術(shù)可以被使用.

          很多WEB程序員熟悉的技術(shù)是將需要訪問的對象放到HttpServletRequest和HttpSession中.這可以通過實現(xiàn)"aware"接口來完成,然后設(shè)置對像,使用特定的名稱訪問.

          如果你想使用內(nèi)建的標(biāo)簽或是引入JSTL支持,訪問數(shù)據(jù)就非常容易了.他們兩個都可以通過值棧直接存取action.唯一的工作就是程序員需要給Action里允許被訪問的需要存取的對象提供getter方法.

          我們將在后面的部分更詳細(xì)的討論值棧.

          Interceptors

          Struts2框架使用攔截器提供了許多特征;例如包含異常處理,文件上傳,生命周期回調(diào)和驗證.攔截器是同Servlet過濾器或是JDKs的代理類相同的概念.它們提供了Action的前處理和后處理的方法.與Servlet過濾器相似,攔截器也可以分層和排序.They have access to the action being executed, as well as all environmental variables and execution properties.

          讓我們開始討論攔截器依賴注入.依賴注入到action當(dāng)中,與我們之前看到的一樣,有兩種不同的形式出現(xiàn).有一些攔截器是我們已經(jīng)提過的:

          Spring框架-ActionAutowiringInterceptor攔截器
          請求字符串和Form值-ParametersInterceptor攔截器
          Servlet基礎(chǔ)對象-ServletConfigInterceptor

          前兩個攔截器獨立工作,不需要Action再做什么,但最后一個卻是不同的.它同下面的接口協(xié)作工作:

          SessionAware-通過一個Map來提供對所有Session屬性的訪問
          ServletRequestAware-提供對HttpServletRequest對象的訪問
          RequestAware-通過一個Map來提供對所有Request屬性的訪問
          ApplicationAware-通過一個Map來提供對所有Application屬性的訪問
          ServletResponseAware-提供對ServletResponse對象的訪問
          ParameterAware-通過一個Map來提供對所有請求字符串和Form值的訪問
          PrincipalAware-提供對PrincipleProxy對象的訪問;這個對象實現(xiàn)了HttpServletRequest對象的規(guī)則和角色的方法, 但提供個代理,允許獨立于Action的實現(xiàn)
          ServletContextAware-提供對ServletContext對象的訪問

          為了將正確的數(shù)據(jù)注入到Action當(dāng)中,它需要實現(xiàn)必需的接口.

          Configuration

          如果我們想要能夠注入(或任何其他由攔截器提供的功能)到我們的Action,我們需要提供配置.像其他元素一樣,大多數(shù)的攔截器已經(jīng)為你配置好了.只需要你的Actions的包繼承自"struts-default"包即可.

          要配置一個新的攔截器,我們首先需要定義這個攔截器.將<interceptors … />和<interceptor …/>標(biāo)簽直屬<package>標(biāo)簽.對于上面提到的Spring框架攔截器,它的配置如下:

           

          1<interceptors>
          2    …
          3    <interceptor name="autowiring"
          4        class="interceptor.ActionAutowiringInterceptor"/>
          5</interceptors>

           

          我們同樣需要確認(rèn)將攔截器應(yīng)用到需要它的Action上.這可以通過兩種方法實現(xiàn).第一種是將攔截器分配給每個Action:

           

          1<action name="my" class="com.fdar.infoq.MyAction" >
          2    <result>view.jsp</result>
          3    <interceptor-ref name="autowiring"/>
          4</action>

           

          使用這種配置,可以被應(yīng)用到Action上的攔截器沒有數(shù)量的限制.現(xiàn)在所需要的就是排列攔截器的順序,它們都將被執(zhí)行.

          第二種方式是為當(dāng)前的包分配默認(rèn)的攔截器:

          <default-interceptor-ref name="autowiring"/>


          這個定義是直屬<package ... />標(biāo)簽 的,并且只能有一個攔截器被定義成默認(rèn)的.

          現(xiàn)在已將攔截器配置到了Action映射上了,它將在每個映射的URL請求時被執(zhí)行.但是這樣有一些限制,更多的時候,我們需要將多個攔截器指派給一個Action.事實上,Struts2里基礎(chǔ)的功能攔截器有很多,給每個Action指派7,8個攔截器也不是不可能的事.你可以假設(shè)一下,為每個Action配置各個攔截器,很快就會變得極難管理.因為這個原因,可使用攔截器棧來管理攔截器.這里有個例子,來自struts-default.xml文件:

           

          1<interceptor-stack name="basicStack">
          2    <interceptor-ref name="exception"/>
          3    <interceptor-ref name="servlet-config"/>
          4    <interceptor-ref name="prepare"/>
          5    <interceptor-ref name="checkbox"/>
          6    <interceptor-ref name="params"/>
          7    <interceptor-ref name="conversionError"/>
          8</interceptor-stack>

           

          這個配置節(jié)點在<package ... />節(jié)點之下.每個<interceptor-ref … />標(biāo)簽引用一個攔截器或是一個在當(dāng)前攔截器棧之前定義的攔截器棧.

          我們已經(jīng)看過如何將攔截器應(yīng)用于Action之上,應(yīng)用攔截器棧沒有什么不同.事實上,我們正是使用相同的標(biāo)簽:

           

          1<action name="my" class="com.fdar.infoq.MyAction" >
          2    <result>view.jsp</result>
          3    <interceptor-ref name="basicStack"/>
          4</action>

           

          這種做法對于默認(rèn)的攔截器同樣有效-簡單的使用一個攔截器棧要優(yōu)于使用單個的攔截器.

          <default-interceptor-ref name="basicStack"/>


          所以在配置實始攔截器和攔截器棧的時候,保證配置所有的攔截器和攔截器棧的名稱唯一是非常重要的.

          Implementing Interceptors

          在你的應(yīng)用中使用自定義的攔截器為應(yīng)用提供cross-cutting特征是一個非常好的方式.只需要實現(xiàn)來自XWork框架的一個簡單的接口.它只有3個方法:

           

          1public interface Interceptor extends Serializable {
          2    void destroy();
          3    void init();
          4    String intercept(ActionInvocation invocation) throws Exception;
          5}

           

          事實上,如果實始化和清除方法不是必需的,可以替代成擴(kuò)展AbstractInterceptor類.這個類為"destroy"和"init"方法提供了默認(rèn)的空實現(xiàn).

          ActionInvocation對象提供了對運行環(huán)境的訪問.它允許訪問Action本身,context(對于一個WEB應(yīng)用,包含請求參數(shù),session參數(shù)等),action執(zhí)行的結(jié)果和調(diào)用action的方法,并確定action是否已經(jīng)被調(diào)用.

          我們已經(jīng)知道如何來配置攔截器了,配置自定義攔截的方式完全相同.如果你創(chuàng)建了你自己的攔截器,你將同樣會考慮創(chuàng)建自定義的攔截器棧.這樣你將確認(rèn)你的應(yīng)用保持一致,新的攔截器可以處理所有需要他的actions.

          Value Stack / OGNL

          這個部分包括相關(guān)緊密地的二個概念.值棧正確的說應(yīng)該是棧對象.OGNL則是Object Graph Navigational Language的縮寫,提供在值棧里標(biāo)準(zhǔn)的訪問對象的方式.

          值棧由下面羅列的對像組成:
          1.Temporary Objects-在執(zhí)行期間創(chuàng)建臨時對象,并將其放入值棧;一個例子是將當(dāng)前集合中迭代的值循環(huán)的放到JSP標(biāo)簽中
          2.The Model Object-如果模型對象正在使用,那么當(dāng)前模型在action之前放入值棧
          3.The Action Object-正在被執(zhí)行的Action
          4.Named Objects-這些對象包括#application,#session,#request,#attr和#parameters還有相應(yīng)的Servlet范圍

          訪問值棧可以通過許多不同的方式完成.大多數(shù)常用的方式是通過JSP提供的標(biāo)簽,Velocity和Freemarker.HTML標(biāo)簽一般被用于訪問值棧中對象的屬性;控制標(biāo)簽(像if, elseif和iterator)用于表達(dá)式;數(shù)據(jù)標(biāo)簽可以操作棧本身(通過set和push).

          在使用值棧的時候,不需要知道目標(biāo)對象存在于哪個范圍之內(nèi).如果你想取屬性"name"的值,你可以向值棧查詢這個屬性.每個棧元素,按照提供的順序,被詢問它是否存在property.如果存在,則返回這個值.如果不存在,則下一個元素會被查詢.這將繼續(xù)一直到棧里的元素全被查詢.這是一個非常好的特征,你不需要知道這個值是哪里的-action,model或是HTTP請求-你只需要知道如果這個值存在,它就將被返回.

          這是downside.如果property是常用的(例如"id"),而且你想從特定的對象(比方說action)取值,也就是說不是值棧中第一個遇到這個property的對象,返回的值可能與你的預(yù)期值不同.想要返回一個"id"的值,但它可能來自于JSP標(biāo)簽,臨時對象,或是來自模型對象.OGNL正好有一種訪問對象的屬性的方法,我們可以在這里使用對我們有利的.如果我們知道棧在action中的深度,我們可以使用"[2].id"來替換"id".

          事實上,OGNL是一種非常有特色的表達(dá)式語言.使用圓點符號對對象進(jìn)行導(dǎo)航(例如,使用表達(dá)式"person.address"來替代"getPerson().getAddress()"),OGNL支持的特征如類型轉(zhuǎn)換,方法調(diào)用,集合的處理和創(chuàng)建,projection across ollections,表達(dá)式賦值和lambda表達(dá)式.完整的語言指南可以查看http://www.ognl.org/2.6.9/Documentation/html/LanguageGuide/index.html.

          Result Types

          到目前為止,我們只展示了配置Action的結(jié)果通過JSP渲染呈遞給用戶.這是一個方案,但卻不是唯一的.事實上,Struts2支持多種類型的結(jié)果.它們可以是可視的,或是可以與環(huán)境交互.

          為action執(zhí)行的結(jié)果配置一個指定的類型,將使用"type"屬性.如果沒有應(yīng)用這個屬性,默認(rèn)的"dispatcher"類型將被使用-這將呈遞一個JSP的結(jié)果.如何配置action看起來像下面這樣:

           

          1<action name="my" class="com.fdar.infoq.MyAction" >
          2    <result type="dispatcher">view.jsp</result>
          3</action>

           

          Configuration

          結(jié)果類型配置在<package ... />標(biāo)簽內(nèi).這個配置與攔截器的配置相似.一個"name"屬性提供了一個結(jié)果類型的唯一標(biāo)識,并且"class"標(biāo)簽提供實現(xiàn)類.這還有第三個屬性"default"-這允許修改默認(rèn)的結(jié)果類型.如果一個WEB應(yīng)用基于Velocity而不是JSP,修改默認(rèn)的將比輸入配置信息省時.

           

          1<result-types>
          2    <result-type name="dispatcher" default="true"
          3        class="….dispatcher.ServletDispatcherResult"/>
          4    <result-type name="redirect"
          5        class="….dispatcher.ServletRedirectResult"/>
          6    …
          7</result-types>

           

          Implementing Result Types

          與攔截器相似,它可能創(chuàng)建出你自己的結(jié)果類型并將它們配置到你的WEB應(yīng)用中.一些常用的結(jié)果類型已經(jīng)存在,所以,在你創(chuàng)建自己的之前,你應(yīng)該先看看你想創(chuàng)建的類型是否已經(jīng)存在.

          為了創(chuàng)建一個新的結(jié)果類型,實現(xiàn)Result接口即可.

          1public interface Result extends Serializable {
          2    public void execute(ActionInvocation invocation) throws Exception;
          3}

           

          ActionInvocation對象提供了對運行環(huán)境的訪問,允許一個新的結(jié)果類型訪問來自剛剛運行的action的信息,也可以訪問執(zhí)行action的上下文.上下文包括了HttpServletRequest對象,可提供對當(dāng)前請求的輸出流的訪問.

          上一章:Starting Struts2--Core Components(2)
          下一章:Starting Struts2--Core Components(4)

          PS:唉,進(jìn)度很慢,第三章還沒有結(jié)束,不過還好,還差一小部分就能結(jié)束了

          Feedback

          # re: Starting Struts2--Core Components(3)  回復(fù)  更多評論   

          2007-08-10 08:30 by icc
          不錯,多謝!!

          # re: Starting Struts2--Core Components(3)  回復(fù)  更多評論   

          2007-08-10 09:54 by paul
          struts2也支持xwork的model driven的寫法,只要在你的action中實現(xiàn)ModelDriven接口就可以啦。所以property driven和model driven在struts2中都支持,所以client可以有兩種選擇,

          # re: Starting Struts2--Core Components(3)  回復(fù)  更多評論   

          2007-08-10 10:36 by paul
          期待你的s2所說的零配置的講解啊,annotation,給個例子啊

          posts - 47, comments - 124, trackbacks - 0, articles - 0

          Copyright © puras

          主站蜘蛛池模板: 宝兴县| 彭水| 阳新县| 额济纳旗| 青州市| 南充市| 孝义市| 四子王旗| 揭西县| 黑龙江省| 耒阳市| 固原市| 黄山市| 乌兰察布市| 体育| 龙门县| 惠东县| 名山县| 漳浦县| 大石桥市| 石楼县| 会理县| 安化县| 平山县| 石棉县| 富阳市| 万州区| 长海县| 青海省| 胶南市| 米林县| 阿巴嘎旗| 内乡县| 红桥区| 株洲市| 巨鹿县| 丹东市| 缙云县| 克山县| 威远县| 钦州市|