Struts2-值棧與OGNL

OGNL表示式使用 和 值棧
OGNL是Object Graphic Navigation Language(對象圖導(dǎo)航語言)的縮寫咖楣,它是一個開源項目柏腻。 Struts2框架使用OGNL作為默認(rèn)的表達(dá)式語言。
* xwork 提供 OGNL表達(dá)式
* ognl-3.0.5.jar
OGNL 是一種比EL 強(qiáng)大很多倍的語言

OGNL 提供五大類功能
1咏尝、支持對象方法調(diào)用茎匠,如xxx.doSomeSpecial()岭辣;
2鼻听、支持類靜態(tài)的方法調(diào)用和值訪問
3财著、訪問OGNL上下文(OGNL context)和ActionContext; (重點(diǎn) 操作ValueStack值棧 )
4撑碴、支持賦值操作和表達(dá)式串聯(lián)
5撑教、操作集合對象。

1醉拓、 使用OGNL訪問 對象方法 和 靜態(tài)方法
* OGNL 在jsp 結(jié)合 struts2 標(biāo)簽庫 使用 伟姐, <s:property value="ognl表達(dá)式" /> 執(zhí)行 ognl表達(dá)式
調(diào)用 實例方法 : 對象.方法() ---- <s:property value="'hello,world'.length()"/>
調(diào)用 靜態(tài)方法 : @[類全名(包括包路徑)]@[方法名] --- <s:property value="@java.lang.String@format('您好,%s','小明')"/>
* 使用 靜態(tài)方法調(diào)用 必須 設(shè)置 struts.ognl.allowStaticMethodAccess=true

2、 訪問OGNL上下文(OGNL context)和ActionContext
OGNL上下文(OGNL context) 對象 ----- 值棧 ValueStack

問題一 : 什么是值棧 ValueStack ?
ValueStack 是 struts2 提供一個接口亿卤,實現(xiàn)類 OgnlValueStack ---- 值棧對象 (OGNL是從值棧中獲取數(shù)據(jù)的 )
每個Action實例都有一個ValueStack對象 (一個請求 對應(yīng) 一個ValueStack對象 )
在其中保存當(dāng)前Action 對象和其他相關(guān)對象 (值棧中 是有Action 引用的 )
Struts 框架把 ValueStack 對象保存在名為 “struts.valueStack” 的請求屬性中,request中 (值棧對象 是 request一個屬性)

問題二 : 值棧的內(nèi)部結(jié)構(gòu) 愤兵?
值棧由兩部分組成
ObjectStack: Struts 把動作和相關(guān)對象壓入 ObjectStack 中--List
ContextMap: Struts 把各種各樣的映射關(guān)系(一些 Map 類型的對象) 壓入 ContextMap 中
Struts 會把下面這些映射壓入 ContextMap 中
parameters: 該 Map 中包含當(dāng)前請求的請求參數(shù)
request: 該 Map 中包含當(dāng)前 request 對象中的所有屬性
session: 該 Map 中包含當(dāng)前 session 對象中的所有屬性
application:該 Map 中包含當(dāng)前 application 對象中的所有屬性
attr: 該 Map 按如下順序來檢索某個屬性: request, session, application

ValueStack中 存在root屬性 (CompoundRoot) 、 context 屬性 (OgnlContext )
* CompoundRoot 就是ArrayList
* OgnlContext 就是 Map
context 對應(yīng)Map 引入 root對象
* context中還存在 request怠噪、 session恐似、application杜跷、 attr傍念、 parameters 對象引用
* OGNL表達(dá)式,訪問root中數(shù)據(jù)時 不需要 #, 訪問 request葛闷、 session憋槐、application、 attr淑趾、 parameters 對象數(shù)據(jù) 必須寫 #
* 操作值棧 默認(rèn)指 操作 root 元素

問題三 : 值棧對象的創(chuàng)建 阳仔,ValueStack 和 ActionContext 是什么關(guān)系 ?
值棧對象 是請求時 創(chuàng)建的
doFilter中 prepare.createActionContext(request, response);
* 創(chuàng)建ActionContext 對象過程中扣泊,創(chuàng)建 值棧對象ValueStack
* ActionContext對象 對 ValueStack對象 有引用的 (在程序中 通過 ActionContext 獲得 值棧對象 )
Dispatcher類 serviceAction 方法中 將值棧對象保存到 request范圍
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

問題四 : 如何獲得值棧對象
獲得值棧對象 有兩種方法
ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
ValueStack valueStack2 = ActionContext.getContext().getValueStack();

問題五: 向值棧保存數(shù)據(jù) (主要針對 root)
兩種方式
// 將數(shù)據(jù)保存root的索引0位置近范,放置到第一個元素 ArrayList add(0,element);
valueStack.push("itcast");

    // 在值棧創(chuàng)建參數(shù)map, 將數(shù)據(jù)保存到map中
    valueStack.set("company", "傳智播客");
    valueStack.set("pany","itcast");
    
在jsp中 通過 <s:debug /> 查看值棧的內(nèi)容 

問題六: 在JSP中獲取值棧的數(shù)據(jù)
訪問root中數(shù)據(jù) 不需要#
訪問 其它對象數(shù)據(jù) 加 #

通過下標(biāo)獲取root中對象
<s:property value="[0].top"/> //取值棧頂對象
直接在root中查找對象屬性 (自上而下自動查找)
valueStack:<s:property value="username"/>

在OgnlContext中獲取數(shù)據(jù)
request:<s:property value="#request.username"/>
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#parameters.cid[0]"/>

================================== valueStack對象 保存在request范圍延蟹, 值棧生命周期 就是 request的生命周期 评矩,值棧的內(nèi)部結(jié)構(gòu)(root、ognlContext) 阱飘、獲取值棧對象斥杜、向值棧保存數(shù)據(jù)虱颗、在JSP顯示值棧的內(nèi)容

3、 值棧在開發(fā)中應(yīng)用
主流應(yīng)用 : 值棧 解決 Action 向 JSP 傳遞 數(shù)據(jù)問題

Action 向JSP 傳遞數(shù)據(jù)處理結(jié)果 蔗喂,結(jié)果數(shù)據(jù)有兩種形式
1) 消息 String類型數(shù)據(jù)
this.addFieldError("msg", "字段錯誤信息");
this.addActionError("Action全局錯誤信息");
this.addActionMessage("Action的消息信息");

  • fieldError 針對某一個字段錯誤信息 (常用于表單校驗)忘渔、actionError (普通錯誤信息,不針對某一個字段 登陸失敗)缰儿、 actionMessage 通用消息

在jsp中使用 struts2提供標(biāo)簽 顯示消息信息
<s:fielderror fieldName="msg"/>
<s:actionerror/>
<s:actionmessage/>

2) 數(shù)據(jù) (復(fù)雜類型數(shù)據(jù))
使用值棧 valueStack.push(products);

哪些數(shù)據(jù)默認(rèn)會放入到值棧 畦粮??乖阵?
1)每次請求锈玉,訪問Action對象 會被壓入值棧 ------- DefaultActionInvocation 的 init方法 stack.push(action);
* Action如果想傳遞數(shù)據(jù)給 JSP,只要將數(shù)據(jù)保存到成員變量义起,并且提供get方法就可以了
2)ModelDriven 接口 有一個單獨(dú)攔截器
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
在攔截器中 拉背,將model對象 壓入了 值棧 stack.push(model);
* 如果Action 實現(xiàn)ModelDriven接口,值棧默認(rèn)棧頂對象 就是model對象

4默终、 值棧的數(shù)據(jù) 通過EL訪問
問題七:為什么 EL也能訪問值棧中的數(shù)據(jù)

StrutsPreparedAndExecuteFilter的doFilter代碼中 request = prepare.wrapRequest(request);
* 對Request對象進(jìn)行了包裝 椅棺,StrutsRequestWrapper
* 重寫request的 getAttribute
Object attribute = super.getAttribute(s);
if (attribute == null) {
attribute = stack.findValue(s);
}
訪問request范圍的數(shù)據(jù)時,如果數(shù)據(jù)找不到齐蔽,去值棧中找
* request對象 具備訪問值棧數(shù)據(jù)的能力 (查找root的數(shù)據(jù))

============================================================================================================================
5两疚、 OGNL表達(dá)式 常見使用

、 % 含滴、$ 符號使用

1) # 的 使用
用法一 # 代表 ActionContext.getContext() 上下文
<s:property value="#request.name" /> ------------> ActionContext().getContext().getRequest().get("name");

request

session

application

attr

parameters

用法二 : 不寫# 默認(rèn)在 值棧中root中進(jìn)行查找
<s:property value="name" /> 在root中查找name屬性

  • 查詢元素時诱渤,從root的棧頂元素 開始查找, 如果訪問指定棧中元素 <s:property value="[1].name" /> 訪問棧中第二個元素name屬性
  • 訪問第二個元素對象 <s:property value="[1].top" />

用法三 :進(jìn)行投影映射 (結(jié)合復(fù)雜對象遍歷 )
1)集合的投影(只輸出部分屬性
<h1>遍歷集合只要name屬性</h1>
<s:iterator value="products.{name}" var="pname">
<s:property value="#pname"/>
</s:iterator>
2)遍歷時谈况,對數(shù)據(jù)設(shè)置條件
<h1>遍歷集合只要price大于1500商品</h1>
<s:iterator value="products.{?#this.price>1500}" var="product">
<s:property value="#product.name"/> --- <s:property value="#product.price"/>
</s:iterator>
3)綜合
<h1>只顯示價格大于1500 商品名稱</h1>
<s:iterator value="products.{?#this.price>1500}.{name}" var="pname">
<s:property value="#pname"/>
</s:iterator>

用法四: 使用#構(gòu)造map集合
經(jīng)常結(jié)合 struts2 標(biāo)簽用來生成 select勺美、checkbox、radio
<h1>使用#構(gòu)造map集合 遍歷</h1>
<s:iterator value="#{'name':'aaa','age':'20', 'hobby':'sport' }" var="entry">
key : <s:property value="#entry.key"/> , value: <s:property value="#entry.value"/>

</s:iterator>

  1. %的使用
    用法一: 結(jié)合struts2 表單表單使用碑韵, 通過%通知struts赡茸, %{}中內(nèi)容是一個OGNL表達(dá)式,進(jìn)行解析
    <s:textfield name="username" value="%{#request.username}"/>
    用法二: 設(shè)置ognl表達(dá)式不解析 %{'ognl表達(dá)式'}
    <s:property value="%{'#request.username'}"/>

3)$的使用
用法一 :用于在國際化資源文件中祝闻,引用OGNL表達(dá)式
在properties文件 msg=歡迎您, ${#request.username}
在頁面
<s:i18n name="messages">
<s:text name="msg"></s:text>
</s:i18n>
* 自動將值棧的username 結(jié)合國際化配置信息顯示
用法二 :在Struts 2配置文件中占卧,引用OGNL表達(dá)式

<param name="contentType">${contentType}</param>
* ${contentType} 讀取值棧中contentType數(shù)據(jù),在Action提供 getContentType 因為Action對象會被壓入值棧联喘,
contentType是Action屬性华蜒,從值棧獲得

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市豁遭,隨后出現(xiàn)的幾起案子叭喜,更是在濱河造成了極大的恐慌,老刑警劉巖堤框,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件域滥,死亡現(xiàn)場離奇詭異纵柿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)启绰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門昂儒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人委可,你說我怎么就攤上這事渊跋。” “怎么了着倾?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵拾酝,是天一觀的道長。 經(jīng)常有香客問我卡者,道長蒿囤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任崇决,我火速辦了婚禮材诽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恒傻。我一直安慰自己脸侥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布盈厘。 她就那樣靜靜地躺著睁枕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沸手。 梳的紋絲不亂的頭發(fā)上外遇,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機(jī)與錄音罐氨,去河邊找鬼臀规。 笑死,一個胖子當(dāng)著我的面吹牛栅隐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玩徊,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼租悄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恩袱?” 一聲冷哼從身側(cè)響起泣棋,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎畔塔,沒想到半個月后潭辈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸯屿,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年把敢,在試婚紗的時候發(fā)現(xiàn)自己被綠了寄摆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡修赞,死狀恐怖婶恼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柏副,我是刑警寧澤勾邦,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站割择,受9級特大地震影響眷篇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荔泳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一铅歼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧换可,春花似錦椎椰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至译荞,卻和暖如春瓤的,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吞歼。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工圈膏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人篙骡。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓稽坤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親糯俗。 傳聞我的和親對象是個殘疾皇子尿褪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容