strut2ognl
然而,我認為struts2最復雜難學的是它內置的ognl表達式.這個ognl在我開始學struts2時,讓我云里霧里,不知如何應對.經過幾輪 的翻看書籍,與網上資料查詢,還算是讓我有所明白一點.在此記錄,以便日后溫習,同時,如果這篇文章對各位有哪怕一點幫助,那便是我最大的榮幸.
首先,要知道ognl最主要的功能就是取數據,它可以利用一段簡短的表達式取出各種各樣豐富的數據.其次,它還附帶了一些便捷的功能,如:方法調用、 靜態方法和屬性調用、數值運算……我們最關心的是如何取數據,因此,接下來我將重點介紹如何取數據,至于附帶功能將不做介紹。
知道了ognl最主要的功能是取數據后,那么數據從哪里取呢!ognl會從兩個地方取:一個是Action的實例屬性;另一個是 ValueStack(中文名叫值棧)。ognl會先從前者里面取,如果沒取到再到ValueStack里取。Action的實例屬性好理解,但這個 ValueStack從字面上看,著實不好理解,以致于我將struts2的源碼引進eclipse里,單步調試才算有所啟發。可以將 ValueStack初步理解為一個map,在這個map里存儲了request、session、application、response、 action實例、parameters數組……還有很多你不知道的對象。有了這個map,還愁數據取不到嗎。
注意:將ValueStack初步理解為一個map,只適于初學struts2的人,其實它內部并沒這么簡單。由于水平、時間有限,我并不能掌握其內 部精髓,加上表達能力不佳,怕表達不對誤導大家,所以我們姑且理解ValueStack為一個map吧。如果想更深的了解的ValueStack,請查看 struts2的源碼。
接下來,便是取數據。取action實例的屬性數據與取ValueStack中的數據不一樣,先說取action實例的屬性數據吧。
action實例的屬性數據可以直接在struts2的標簽中通過屬性名取到。如:<s:property value="name"/>、<s:property value="user.password"/>
注意:不要加#號。
再是取ValueStack中的數據。
struts2提供三種方式通過ognl表達式來取ValueStack中的數據:#、%{}、${}
#和%{}需要放到struts2提供的標簽里才生效。如:<s:property value="#name"/>、<s:property value="%{'hello struts2'}"/>
一、最常用的方式是:#
1.#能取request、session、application里的attribute,但需要加前綴。如:<s:property value="#session.name2"/>、<s:property value="#application.name3"/>。如果是取request范圍的attribute,那么不需要加request前綴, 加上反而取不到數據,ognl默認從request里取,如果沒有取到并不會到session或application里取。 如:<s:property value="#name"/>
2.#能取request里的請求參數,但必須加parameters前綴,且取到的是一個數組,所以如果你要得到參數的第一項值,那么還要加下標。 如:<s:property value="#parameters.name[0]"/>。這相當于調用 request.getParameterValues("name")[0];
3.#加attr前綴能按request > session > application順序獲取attribute,這樣當在request中取不到時,會自動向session里取,如果session里也取不到,會 再向application里取。如果取到則返回,不再向上游歷。如:<s:property value="#attr.name"/>
4.#能構造Map,如:<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" /><s:property value="#foobar['foo1']" />
5.#能用于過濾和投影(projecting)集合,如:books.{?#this.price<100}
以上第4、5項功能,我沒有做過多介紹,因為目前為止這兩項功能我使用并不多。
二、%{}的用途是在標簽的屬性為字符串類型時,計算OGNL表達式的值。這個功能目前還沒有深刻體會,故不介紹。
三、${}有兩個主要的用途。
1.用于在國際化資源文件中,引用OGNL表達式。
2.在Struts 2配置文件中,引用OGNL表達式。如 :
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>
以上,其實主要介紹了#的使用,大部分情況下我們只與它打交道,另外兩種方式需要在以后的項目中多多使用才能有所體會。
其實,我是jstl+el的忠實粉絲,在任何項目中,只要能用上jstl標簽的,我決不用其它標簽。因為它是官方標準,還有它簡單且已熟練,我已在眾多項目中實戰演練過,有了它們,我不想在使用其它標簽。
說到了這里,我還是有必要再多說兩句,是不是使用了struts2,就不能再用el來取數據了呢?答案是否定的,完全可以使用el來取數據。 struts2會將ValueStack里的session、application里的attribute完全復制到HttpSession、 ServletContext里,這樣el表達式照樣能取到這兩個Scope里的數據。然而,struts2并沒有將ValueStack里的 request里的attribute復制到HttpServletRequest,這是不是意味著el表達式就不能取request里的數據了呢?還是 可以,不只可以取request里的數據,還可以取action實例的屬性值。神奇吧!奧秘就在struts2對request做了封裝,這個封裝類是 org.apache.struts2.dispatcher.StrutsRequestWrapper,它重寫了getAttribute()方法, 該方法先從真實的request類里取attribute,如果取到則返回,如果沒有取到則從ValueStack里取,現在明白了吧!