(十)Struts2進(jìn)階之OGNL在Struts2中的使用

上篇文章把OGNL單獨(dú)拿出來講了,這篇文章就講講OGNL結(jié)合Struts2的使用较雕。

Struts2中OGNL表達(dá)式必須配合Struts2標(biāo)簽使用碉哑,不然沒什么效果。

(八)Struts2進(jìn)階之值棧詳解這篇文章中我們分析了值棧的結(jié)構(gòu)亮蒋,講了值棧的實(shí)現(xiàn)類是OgnlValueStack類扣典,它包含兩部分,分別是root(對(duì)應(yīng)CompoundRoot類)和context(對(duì)應(yīng)OgnlContext類)慎玖。

在每次調(diào)用核心控制器時(shí)贮尖,在它的doFilter方法中有這么一行代碼

prepare.createActionContext(request, response);

這行對(duì)于我們理解值棧很關(guān)鍵啊,本來應(yīng)該放在值棧里說的凄吏。远舅。。

首先先捋一捋ActionContext是什么玩意痕钢,上篇文章單純講OGNL的時(shí)候說了图柏,它有一個(gè)執(zhí)行的上下文環(huán)境OgnlContext,它里面有一個(gè)根對(duì)象和若干個(gè)普通對(duì)象任连。

那么在Struts2中蚤吹,要使用OGNL,也得給它一個(gè)上下文環(huán)境随抠,其實(shí)我看網(wǎng)上很多文章說ActionContext是上下文環(huán)境裁着,但我認(rèn)為應(yīng)該是OgnlValueStack類,它里面有這么兩行代碼

CompoundRoot root;
transient Map<String, Object> context;

分別代表值棧的root和context拱她。不過我們可以在ActionContext類中取得值棧對(duì)象二驰。

下面開始說。

1.Struts2中的OGNL

Struts2中的OGNL比單純的OGNL要更強(qiáng)大秉沼,上篇文章中桶雀,我們說了只能有一個(gè)root對(duì)象,而在OGNL中唬复,可以有多個(gè)root對(duì)象矗积。root對(duì)應(yīng)的實(shí)現(xiàn)類是CompoundRoot,該類實(shí)質(zhì)是List敞咧,所有能有多個(gè)root對(duì)象棘捣。在Strtus2中的Root使用的是CompoundRoot對(duì)象,而CompoundRoot繼承了ArrayList休建,所以他可以存儲(chǔ)一系列的對(duì)象乍恐,這些對(duì)象可以看作是OGNL中的root對(duì)象评疗。當(dāng)我們當(dāng)問某個(gè)屬性時(shí),CompoundRootAccessor對(duì)象實(shí)例會(huì)負(fù)責(zé)在CompoundRoot對(duì)象中找到包含我們指定屬性的對(duì)象禁熏。

2.再說ValueStack

對(duì)于用戶的每個(gè)action請(qǐng)求壤巷,Struts2在執(zhí)行相應(yīng)的方法之前,都會(huì)新建一個(gè)valuestack對(duì)象瞧毙,其實(shí)這個(gè)創(chuàng)建的過程就在Struts2的核心控制器里的doFilter方法中胧华,也就是從上面的那行代碼開始的,它會(huì)把request宙彪、session矩动、application、atrr释漆、parameters放入context中悲没。

valueStack的內(nèi)部包含兩個(gè)邏輯部分,一個(gè)叫做Object Stack(root)男图,另一個(gè)叫做Context Map(context)示姿。Struts2將動(dòng)作和相關(guān)對(duì)象壓入Object Stack,把各種各樣的映射關(guān)系(Map類型的對(duì)象)壓入Context Map逊笆。其中的Object Stack中的對(duì)象都相當(dāng)于OGNL中的”root”對(duì)象栈戳,因此對(duì)他們可以直接訪問。如果要訪問Context Map中的對(duì)象难裆,那么就得在OGNL表達(dá)式前面加上”#”符號(hào)子檀。如果沒有加”#”,那么Struts2默認(rèn)會(huì)在Object Stack中進(jìn)行搜索乃戈。


36.jpg

Strut2會(huì)把下面的這些映射關(guān)系壓入到Context Map中:
(1) parameters:這個(gè)Map中包含當(dāng)前請(qǐng)求的請(qǐng)求參數(shù)
(2) request:包含當(dāng)前請(qǐng)求的所有屬性
(3) session:包含當(dāng)前請(qǐng)求的會(huì)話的所有屬性
(4) application:包含當(dāng)前應(yīng)用程序的ServletContext屬性
(5) attr:這個(gè)Map用來按照這個(gè)順序來檢索某個(gè)屬性:request褂痰、session、application
注意:請(qǐng)求參數(shù)總是返回一個(gè)String類型的數(shù)組症虑。比如我們要想知道請(qǐng)求參數(shù)的個(gè)數(shù)缩歪,那么正確的表達(dá)式應(yīng)該是#parameters.count[0],而不是#parameters.count谍憔。

3.使用OGNL獲取值棧中的屬性值

34.png

獲取root中的值驶冒,我們不需要加#符號(hào),這和上篇文章是一樣的道理韵卤。

下面看看代碼
新建一個(gè)User類,有username和password兩個(gè)屬性

@SuppressWarnings("serial")
public class User implements Serializable{
    private String username;
    private String password;
    
    public User() {}

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

新建一個(gè)OGNLAction類崇猫,實(shí)現(xiàn)了三個(gè)接口沈条,分別用于獲取request,session和application诅炉,另外還有一個(gè)list蜡歹。

@SuppressWarnings("serial")
public class OGNLAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware {
    // 這里的值會(huì)被放入Object Stack(root)中屋厘,記得提供get方法,不然無法取值
    private List<User> s1;
    // 這里的值會(huì)被放入Context Map(context)中
    private Map<String, Object> applicationMap;
    // 這里的值會(huì)被放入Context Map(context)中
    private Map<String, Object> sessionMap;
    // 這里的值會(huì)被放入Context Map(context)中
    private Map<String, Object> requestMap;
    @Override
    public String execute() throws Exception {
        User u1 = new User("liu", "12345");
        User u2 = new User("xu", "123456");
        User u3 = new User("guo", "520520");
        s1 = new ArrayList<User>();
        Collections.addAll(s1, u1, u2, u3);
        applicationMap.put("users", s1);
        sessionMap.put("users", s1);
        requestMap.put("users", s1);
        return SUCCESS;
    }
    
    @Override
    public void setApplication(Map<String, Object> application) {
        this.applicationMap = application;
    }
    
    @Override
    public void setRequest(Map<String, Object> request) {
        this.requestMap = request;
    }
    
    @Override
    public void setSession(Map<String, Object> session) {
        this.sessionMap = session;
    }

    public List<User> getS1() {
        return s1;
    }

    public void setS1(List<User> s1) {
        this.s1 = s1;
    }
}

在struts.xml中配置action

<action name="OGNL" class="com.codeliu.action.OGNLAction">
    <result>/index.jsp</result>
</action>

新建一個(gè)index.jsp

<body>
    <s:debug></s:debug>
    <s:property value="s1[0].username"/> or <s:property value="#request.users[1].username"/>
    or <s:property value="#application.users[0].username"/> or <s:property value="#session['users'][0].username"/>
    <br>
    <!-- 遍歷list中的元素 -->
    <s:iterator value="s1" var="user">
        <!-- 說明使用var屬性后月而,值放在了context Map中汗洒,要通過#去獲取 -->
        <s:property value="#user.username"/>&nbsp;<s:property value="#user.password"/><br>
        <!-- 不加#也能獲取到,說明在root中沒有找到父款,回去 context Map中找-->
        <s:property value="username"/>&nbsp;<s:property value="password"/><br>
    </s:iterator>
    
    <!-- 遍歷applicationMap中的元素 -->
    <s:iterator value="#application.users" var="user">
        <s:property value="#user.username"/>&nbsp;<s:property value="#user.password"/><br>
    </s:iterator>
    
    <!-- 遍歷requestMap中的元素 -->
    <s:iterator value="#request.users">
        <s:property value="username"/>&nbsp;<s:property value="password"/><br>
    </s:iterator>
    
    <!-- 遍歷sessionMap中的元素 -->
    <s:iterator value="#session.users">
        <s:property value="username"/>&nbsp;<s:property value="password"/><br>
    </s:iterator>
</body>

啟動(dòng)tomcat后溢谤,結(jié)果如下


38.png

代碼上面的注釋都寫的很清楚,說明什么問題憨攒?

1.除了List世杀,其他的三個(gè)變量的值都放進(jìn)去了Context Map中,要取出來必須加上#肝集。
2.使用遍歷標(biāo)簽瞻坝,如果使用了var屬性,則每次遍歷的值都放入了Context Map中杏瞻,使用#符號(hào)也可以取出來所刀。(不使用也可以,因?yàn)樗趓oot中沒找到捞挥,應(yīng)該就會(huì)去Context Map中找浮创。)
3.action類中,放入root中的數(shù)據(jù)树肃,比如上面的list蒸矛,記得要有相應(yīng)的get方法,否則無法取到值胸嘴。
4.使用#session['users'][0].username也可以獲取到屬性的值

4.調(diào)用靜態(tài)方法和靜態(tài)字段

其實(shí)在Struts2中OGNL調(diào)用靜態(tài)方法雏掠、靜態(tài)字段和上篇文章中講的都一樣。

要注意的是劣像,Struts2默認(rèn)是關(guān)閉調(diào)用靜態(tài)方法的功能乡话,所以要使用,得先打開耳奕。

<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

對(duì)于值棧中的靜態(tài)屬性和方法,直接使用它們的名稱即可屋群。

    <!-- 調(diào)用Java API的靜態(tài)變量和靜態(tài)方法 -->
    <s:property value="@java.lang.Math@PI"/>
    <br>
    <s:property value="@java.lang.Math@floor(4.3)"/><br>
    
    <!-- 調(diào)用自己寫的類中的靜態(tài)字字段和靜態(tài)方法 -->
    <s:property value="myName"/><br>
    <s:property value="getMyName()"/>

5.投影和過濾

和上篇文章講的也一樣闸婴。

6.# $ %的使用

“#”的作用
(1)訪問非root對(duì)象的屬性。例如:#session[“userName”]
(2)對(duì)集合進(jìn)行投影與選擇(具體可看上篇文章)
(3)構(gòu)造對(duì)象(具體可看上篇文章),
“%”的作用
在標(biāo)簽的屬性值被理解為字符串類型時(shí)烙心,告訴執(zhí)行環(huán)境%{}里的是OGNL表達(dá)式 <s:property value="%{#foobar['foo1']}" />
“$”的作用
(1)在配置文件中引用OGNL表達(dá)式(訪問Action的屬性)柏靶。
(2)在國(guó)際化資源文件中引用OGNL表達(dá)式(學(xué)習(xí)國(guó)際化時(shí)會(huì)學(xué)到)

7.this指針

在很多編程語(yǔ)言中弃理,都有this指針的概念,它表示調(diào)用當(dāng)前函數(shù)(方法)的對(duì)象屎蜓。那么在OGNL中也有類似的概念痘昌。
我們已經(jīng)學(xué)過,OGNL表達(dá)式是以”.”進(jìn)行串聯(lián)的的一個(gè)串字符串表達(dá)式炬转。這個(gè)表達(dá)式在被執(zhí)行的時(shí)候辆苔,從左到右,每一次計(jì)算都會(huì)返回一個(gè)臨時(shí)的當(dāng)前對(duì)象扼劈,并在此臨時(shí)對(duì)象上再次進(jìn)行調(diào)用驻啤,直到執(zhí)行完畢。這個(gè)臨時(shí)的當(dāng)前變量就存儲(chǔ)在一個(gè)叫做this的變量中荐吵,這個(gè)this變量我們就叫它this指針骑冗。通過使用this指針,我們可以使OGNL更加靈活先煎,更加強(qiáng)大贼涩。
注:使用this指針時(shí),必須在this前面加”#”薯蝎,即this指針必須以“#this”的形式出現(xiàn)遥倦。
例如:group.userList.size().(#this+1).toString()

上篇文章中講投影和過濾的時(shí)候使用了this指針



參考文章
https://blog.csdn.net/xiaokang123456kao/article/details/59483038
https://blog.csdn.net/yu102655/article/details/52182801

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市占锯,隨后出現(xiàn)的幾起案子袒哥,更是在濱河造成了極大的恐慌,老刑警劉巖消略,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堡称,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡艺演,警方通過查閱死者的電腦和手機(jī)粮呢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門婿失,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啄寡,你說我怎么就攤上這事×ㄕ眨” “怎么了挺物?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)飘弧。 經(jīng)常有香客問我识藤,道長(zhǎng),這世上最難降的妖魔是什么次伶? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任痴昧,我火速辦了婚禮,結(jié)果婚禮上冠王,老公的妹妹穿的比我還像新娘赶撰。我一直安慰自己,他們只是感情好柱彻,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布豪娜。 她就那樣靜靜地躺著,像睡著了一般哟楷。 火紅的嫁衣襯著肌膚如雪瘤载。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天卖擅,我揣著相機(jī)與錄音鸣奔,去河邊找鬼。 笑死惩阶,一個(gè)胖子當(dāng)著我的面吹牛挎狸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琳猫,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼伟叛,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了脐嫂?” 一聲冷哼從身側(cè)響起统刮,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎账千,沒想到半個(gè)月后侥蒙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匀奏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年鞭衩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡论衍,死狀恐怖瑞佩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坯台,我是刑警寧澤炬丸,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站蜒蕾,受9級(jí)特大地震影響稠炬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咪啡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一首启、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撤摸,春花似錦毅桃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冕象,卻和暖如春代承,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背渐扮。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工论悴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人墓律。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓膀估,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親耻讽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子察纯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360