posts - 78, comments - 34, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          2010-02-21 傳智播客—Struts2

          Posted on 2010-02-22 16:59 長城 閱讀(742) 評論(0)  編輯  收藏

          Struts2第二天,大家似乎沒有從年假中蘇醒過來,上課顯得有些疲憊。不過還好,聽課效果還不錯。今日的主要內容是OGNLStruts2使用OGNL訪問contextMapvalueStack。老張很執著,他在研究Struts2時遇到的一些問題,一定要解決,并且要詳細解決。通過他在講課中,我們可以看出這一點。有開發經驗的人都知道,我們時而被陌生技術的一個小細節搞的暈頭轉向,耗費了大半天的時間我們才發現這個細節性的錯誤。我們一般都是這么熬出來的,老張也不例外。


          我們在聽老師講課時或在網上看視頻時,都感覺學習起來十分容易。卻很少有人能感受那些認真負責老師在課后付出的心血。老張為了準備一天的課程內容,使用了三天時間來備課并且課程內容他以前也講過。這一點不僅體現在老張的身上,其他老師也是這樣。讓我們為那些認真負責的老師敬禮,并問候一聲:“過年好,您辛苦了!”。


          一、ActionContext

          Action環境(com.opensymphony.xwork2.ActionContext),通過我們之前所學的內容。我們知道Context緩存中保存了XXX環境中所需要使用到的重要對象。Struts2中的ActionContext中就保存了Struts2中使用到的重點對象contextMapvalueStack


          老張搞了一個經典的關系圖:


          ActionContext ac = ActionContext.getContext();

          ValueStack vs = ac.getValueStack();

          Map<String, Object> conMap = ac.getContextMap();

          每一個訪問線程具有一個ActionContext對象,它是以單例模式存在的。ActionContext為我們提供了操作valueStackcontextMap的便捷方法。例我們的程序可以與ValueStackContextMap解耦,比如:ac.put(key, value);ac.get(key);...


          通過ActionContext使得我們編寫的Action不必實現任何接口和繼承任何超類,但我們必須在類中使用ActionContext的實例。


          二、Struts2中的OGNL

          OGNL不是Struts2獨創的,而是Struts2中使用OGNL做為操作contextMapvalueStack的方式。OGNLObject-Graph Navigation Language的縮寫,它是一種功能強大的表達式語言(Expression Language,簡稱為EL),通過它簡單一致的表達式語法,可以存取對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。它使用相同的表達式去存取對象的屬性。


          OGNLl基本的語法:

          1. 可以用#key的形式訪問OGNL Context對象中的各個key對應的對象,并可以采用點(.)操作符進行多級導航調用對象的屬性和方法,例如,#application#session.attr1#key1.sayHello();對于map對象,map.attr不是map.getAttr()方法,而是表示map.get(“attr1”)

          2. 如果要訪問根對象的屬性或方法,則可以省略#key,直接訪問該對象的屬性和方法。 struts2修改了OGNL表達式的默認屬性訪問器,它不是直接訪問根對象ValueStack的屬性或方法,而是在ValueStack內部的堆棧中所有對象上逐一查找該屬性或方法,搜索順序是從棧頂對象開始尋找,依次往下,直到找到為止,例如,sayHello()表示調用堆棧中某個對象的sayHello()方法。

          3. 特例:如果引用名前面沒有#,且valueStack中存儲的各個對象沒有該屬性,則把該名稱當作Context對象中的某個key來檢索對應的對象,但這種方式不支持點(.)操作符。


          ValueStack提供了如下一些方法管理其內部的堆棧和關聯的Context

          1. setValueognl表達式尋址到的對象設置屬性值。

          2. FindValue方法使用OGNL表達式獲取結果。

          3. findString方法對findValue方法獲取的結果調用轉換器轉成字符串,如果該對象的類型沒有相關轉換器,則調用toString方法,并返回結果字符串。一個特殊之處:如果不用#前綴訪問ValueStack Context中的對象,則該對象必須是String類型。


          三、Struts2中的struts-tagsOGNL詳細

          要使用struts-tags標簽,必須先引入struts-2.1.7.dtd文檔類型定義文件。

          1. <s:property>用于輸出某個OGNL表達式的值,可以認為其內部使用的是ValueStack對象的findString方法。如果沒有設置value屬性,則輸出ValueStack棧頂的對象。

            特例:如果采用不加#前綴的方式輸出Context中的某個對象,這個對象必須是string類型。

            如:獲取contextMap中的request對象。

            <s:property value="#request" />

          2. <s:push>用于將OGNL表達式的值壓入棧頂,當遇到</s:push>標簽時,從棧頂彈出。

            如:向棧頂壓入了一個字符串——“你好!”。

            <s:push value="'你好!'">

            <s:property value="top" />

            </s:push>

            注意壓入的字符串必須被包含在''中,否則會被OGNL當做名稱到根對象中查找相應的值。

            通過查看<s:push>標簽的幫助,可以知道有一個為top的特殊OGNL表達式,表示棧頂的對象。

            如:

          <s:push value="'你好!'"><s:property name="top"/></s:push>


          1. <s:bean>用于實例化一個JavaBean對象,并將其壓入棧頂。如果設置了var屬性,還會將實例化的對象存儲進ValueStack關聯的Context中。

            如:實例化一個java.util.Date對象,然后將其放入ContextMap中。

            <s:bean name="java.util.Date" var="MyBean">

            <s:property value="#MyBean" />

            </s:bean>

          2. <s:set>用于將某個值存入指定范圍域中,通常用于將一個復雜的ognl表達式用一個簡單的變量來進行引用。

            如:向request域中添加一個名稱為“TestSet”的屬性。

            <s:set scope="request" value="'日期'+#MyBean" name="TestSet">

            <s:property value="#request.TestSet" />

            </s:set>

            scope屬性:指定變量被放置的范圍,該屬性可以接受applicationsessionrequest pageaction。該屬性的默認值為action,文檔說即表示同時存儲進request作用域和OGNL Context中,但實驗結果是只存儲進了OGNL Context中。

            value屬性:賦給變量的ognl表達式結果.如果沒有設置該屬性,則將ValueStack棧頂的值賦給變量。

          3. <s:if/elseif/else>等標簽用于判斷test屬性中指定的ognl表達式的結果是否為true,為真則執行標簽體重的內容。

            如:設置一個VAL,然后判斷VAL的值,并顯示相應的結果。

            <s:set value="'1'" name="VAL"></s:set>

            <s:if test="1 > 2">

            <s:property value="#VAL+'>2'" />

            </s:if>

            <s:elseif test="1 < 2">

            <s:property value="#VAL+'<2'" />

            </s:elseif>

            <s:else>

            <s:property value="#VAL+'=2'" />

            </s:else>

          4. <s:iterator>用于迭代一個OGNL集合,并逐一將迭代出來的元素壓入棧頂和彈棧。

            如:獲取request中的所有屬性,并且使表格奇數行顏色為#f3c3c3,偶數行顏色為#c3f3f3

            <table>

            <tr>

            <td>Key</td><td>Value</td>

            </tr>

            <s:iterator value="#request" status="status">

            <tr bgcolor='<s:property value="#status.odd ? '#f3c3c3':'#c3f3f3'"/>' >

            <td><s:property value="key"/></td>

            <td><s:property value="value"/></td>

            </tr>

            </s:iterator>

            </table>

            status屬性:創建代表當前迭代狀態的IteratorStatus對象,并指定將其存儲進ValueStack Context中時的key。它與官方給出的幫助文檔的說明不同,官方存在錯誤!

          5. <s:url><s:a>

            使用這兩個標簽可以帶給我們極大的方便,使用他們的好處有:

            使用<s:url namespace=“” action=“” method=“”/>不用關心web應用程序的路徑和Action映射的擴展名。<s:url>中沒有指定namespace屬性時,將根據瀏覽器當前所訪問的url地址來推測包名,并與action屬性指定的內容一起生成最終的url地址。

            可以自動附加jsessionid參數進行url重寫。

            可以對參數信息進行url編碼。 (jstl中的<c:url>標準標簽也有<s:url>標簽的后兩個作用。)

            直接使用<s:url />標簽可以獲得當前地址,只有使用includeParams屬性會帶上原來的請求參數。大型網站的鏈接地址總是要帶上userid之類的信息。

            如:生成一個訪問我們昨天編寫的HelloWorld請求超連接。

            <s:a namespace="/" action="helloWorld" method="helloWorld">HelloWorld</s:a>

          四、OGNL中的語法細節

          1.參看ognl的參考手冊

          類似EL表達式的JavaBean屬性訪問和索引訪問,例如,可以用”#parameter.id[0]”或”#parameter[‘id’][0]”訪問名稱為id的請求參數。

          支持類靜態方法調用和屬性訪問,表達式的格式為@[類全名(包括包路徑)]@[方法名 | 值名],例如:@java.lang.String@format(‘foo %s’, ‘bar’)@cn.itcast.Constant@APP_NAME

          session.attribute[“foo”]等效于session.getAttribute(“foo”)方法。

          OGNL中可以寫很大的整數,例如,<s:property value="%{1111111111111111111111H.bitLength()}"/>,而在java中則不能直接寫1111111111111111111111這么大的整數。

          對當前值可以進一步操作,<s:property value=“110H.intValue().(#this<112?#this*2:#this/2)”/>,其中.(#this …..)部分相當于定義了一個匿名方法,并調用這個匿名方法,方法的代碼就是()里面的內容。


          2.Struts2擴展的特殊功能

          [n]表示從原來堆棧中截取一個子堆棧并對這個子堆棧進行操作,子堆棧為原始堆棧的棧頂開始的索引號為n的元素一直到棧底,例如,[1].age表示從原始堆棧中的索引號為1的對象(即第二個對象)開始查找age屬性,以找到的第一個為準。

          top表示ValueStack棧頂的對象,[0].toptop表示同一個對象。


          3.集合對象與操作

          {}用于創建List集合對象,其中的各個元素之間用逗號分隔:

          <s:set value="{1,3,5,7}" var="list"/>


          采用類似Java的語法創建數組:

          <s:set value="new int[]{1,3,5,7}" var="array"/>

          <s:set value="new int[4]" var="array"/>

          #{}用于創建Map集合對象,其中的各個元素之間用逗號分隔,元素的keyvalue之間采用冒號分隔。另外,還可以指定Map實例對象的類型:

          <s:set value="#{'lhm':96,'zxx':93,'xpc':97}" />

          <s:set value="#@java.util.LinkedHashMap@{'lhm':96,'zxx':93,'xpc':97}" />

          innot in操作符用于判斷某個值是否位于某個集合中。

          <s:set value="new int[]{1,3,5,7}" var="array"/>

          <s:if test="1 in #array">

          <s:property value="#array"/>

          </s:if>

          集合偽屬性:size/isEmpty/iterator/keys/values/next/hasNext

          <s:set value="#{'lhm':96,'zxx':93,'xpc':97}" var="map"/>

          <s:if test="#map.size > 0">

          <s:property value="#map"/>

          </s:if>


          4.集合的投影與過濾

          投影就是拿著集合中的每個元素去進行運算,各個元素運算的結果組成一個新集合,新集合中的元素個數與原始集合中的元素個數相同。

          <s:property value="persons.{name}"/>

          <s:property value="{5,3,2}.{#this*2}"/>

          過濾就是拿著集合中的每個元素去進行布爾運算,運算的結果為true,則將該元素保存到新集合中去。

          ?:獲得所有符合邏輯的元素。

          <s:property value="{5,3,2,0}.{? #this }"/>

          ^:獲得符合邏輯的第一個元素。

          <s:property value="{5,3,2,0}.{^ #this>3 }"/>

          $:獲得符合邏輯的最后一個元素。

          <s:property value="{5,3,2,0}.{$ #this>2 }"/>


          5.類型轉換

          轉換成boolean類型:

          • 整數0轉換為fals

          • 值為0的字符轉化為false

          • Null對象轉化為false

          投影和選擇操作符(e1.{e2} and e1.{?e2})里面的內容會被轉換成集合

          Map會被轉化成其values屬性返回的集合

          數字會被轉換成從0開始到比該數字小1的所有數字的集合。

          單個對象被轉換成僅僅只含有該對象的集合。


          五、在配置文件中使用OGNL

          在下堂課中會做總結!



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


          網站導航:
           
          主站蜘蛛池模板: 东丰县| 鄂温| 渭源县| 浏阳市| 邵阳市| 吴江市| 宁都县| 绥化市| 靖西县| 台中县| 孝昌县| 桃园县| 监利县| 安塞县| 北辰区| 新乐市| 包头市| 涟源市| 海口市| 雅江县| 文水县| 桦甸市| 锡林浩特市| 云梦县| 怀柔区| 邮箱| 梁河县| 米易县| 靖江市| 榆中县| 厦门市| 台湾省| 东台市| 华坪县| 龙泉市| 铜川市| 东乌珠穆沁旗| 越西县| 丹凤县| 北辰区| 抚顺县|