4. ValueStack 和 OGNL

1. 屬性哪來的

  • 當(dāng)我們通過Action處理完用戶請求以后主守,可以直接在頁面中獲取到 action 的屬性值妖混。
  • 如果我們在頁面中嘗試遍歷四個域中的屬性少漆,會發(fā)現(xiàn)域中并沒有username之類的Action中的屬性厅须。
  • 但是我們自己又沒有在域中進(jìn)行設(shè)置侧馅,經(jīng)過研究發(fā)現(xiàn)request域中出現(xiàn)了一個奇怪屬性
    • 屬性的名字:struts.valueStack
    • 屬性的類型:OgnlValueStack
  • ValueStack翻譯過叫做值棧危尿,顧名思義就是存儲值的棧
  • Struts在每次處理請求都會創(chuàng)建一個新的ValueStack用來存儲這個請求過程中所要用到的屬性及對象。
    像我們熟悉ActionContext就是值棧的一部分馁痴。

2. ValueStack(值棧)

  • 所謂值棧就是一個 OgnlValueStack 類型的對象谊娇,他以struts.valueStack為鍵保存在request域中。Struts2 會將 Action 的實例保存值棧中罗晕。
  • 值棧實際是由兩部分組成 Object Stack (CompoundRoot )Map Context (Map<String, Object>
    • context是一個Map济欢,里邊保存著三個域赠堵、請求參數(shù)等對應(yīng)的Map對象。
    • root 實際就是一個List法褥,Action對象就保存在這個List中茫叭。
  • ObjectStack: Struts 把 Action 和相關(guān)對象壓入 ObjectStack 中
  • ContextMap: Struts 把各種各樣的映射關(guān)系(一些 Map 類型的對象) 壓入 ContextMap 中. 實際上就是對 ActionContext 的一個引用
    • 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
  • ContextMap實際上之前我們就使用過,我們使用的 ActionContext 就包含一個ContextMap
  • 我們可以查看一下 CompoundRoot 對象半等,實際上是一個List
  • root (CompoundRoot)就是Struts2存儲Action實例的地方揍愁。當(dāng)我們在JSP中獲取Action中的屬性時,實際上就是去root中進(jìn)行查找杀饵。
  • 但是我們查看方法會發(fā)現(xiàn)莽囤,CompoundRoot 每次都是從棧頂取得對象
/**
 * A Stack that is implemented using a List.
 * 
 * @author plightbo
 * @version $Revision$
 */
public class CompoundRoot extends CopyOnWriteArrayList<Object> {
    private static final long serialVersionUID = 8563229069192473995L;
    public CompoundRoot() {
    }
    public CompoundRoot(List<?> list) {
        super(list);
    }
    public CompoundRoot cutStack(int index) {
        return new CompoundRoot(subList(index, size()));
    }
    public Object peek() {
        return get(0);
    }
    public Object pop() {
        return remove(0);
    }
    public void push(Object o) {
        add(0, o);
    }
}
  • 值棧的結(jié)構(gòu)

  • 在Servlet我們屬性HttpServletRequest實際已經(jīng)被Struts2用 org.apache.struts2.dispatcher.StrutsRequestWrapper 給包裝了(裝飾者模式)

  • 我們的request的getAttributes方法已經(jīng)被Struts重寫。

  • 新的getAttribute方法

    • 首先切距,從request域中查找屬性朽缎,如果有直接返回。
    • 然后蔚舀,如果域中沒有找到指定屬性饵沧,則去值棧中查找(這里的值棧主要指CompoundRoot),
    • 因為值棧中可能有多個對象赌躺,所以會先從索引值為0的對象開始找狼牺,直到找到了需要的屬性,如果找到直接返回礼患。
    • 最后是钥,如果值棧中依然沒有找到指定屬性接下來去context中查找,如果找到直接返回缅叠,如果也沒找到則直接返回null悄泥。

3. OGNL (Object-Graph Navigation Language)

  • Object-Graph Navigation Language
  • 這是一種從Java對象中獲取或設(shè)置屬性的表達(dá)式語言。
  • Struts2內(nèi)部使用OGNL表達(dá)式從而大大增強了Struts2的數(shù)據(jù)訪問功能肤粱。
  • Struts2 利用 s:property 標(biāo)簽和 OGNL 表達(dá)式來讀取值棧中的屬性值

  1. 值棧中的屬性值:
    • 對于對象棧: 對象棧中某一個對象的屬性值
    • Map 棧: request, session, application 的一個屬性值 或 一個請求參數(shù)的值.
  2. 讀取對象棧中對象的屬性:
    • 若想訪問 Object Stack 里的某個對象的屬性. 可以使用以下幾種形式之一:
      • object.propertyName ;
      • object['propertyName'] ;
      • object["propertyName"]
    • ObjectStack 里的對象可以通過一個從零開始的下標(biāo)來引用. ObjectStack 里的棧頂對象可以用 [0] 來引用,
    • 它下面的那個對象可以用 [1] 引用.
      • [0].message
      • [n] 的含義是從第 n 個開始搜索, 而不是只搜索第 n 個對象
    • 若從棧頂對象開始搜索, 則可以省略下標(biāo)部分: message
    • 結(jié)合 s:property 標(biāo)簽: <s:property value="[0].message" /> <s:property value="message" />
    • 默認(rèn)情況下, Action 對象會被 Struts2 自動的放到值棧的棧頂.
  3. 我們可以試著改變值棧的棧頂對象
 //改變對象棧弹囚,棧頂?shù)膶ο?ActionContext context = ActionContext.getContext();
ValueStack valueStack = context.getValueStack();
valueStack.push(User.builder().username("豬八戒").address("高老莊").build());
  1. 獲取對象棧中的數(shù)據(jù):
<!-- 可以直接獲取棧頂對象的屬性,如果棧頂對象沒有就會繼續(xù)往下找领曼,再沒有就從Map棧中找 -->
用戶名 : <s:property value="user.username"></s:property> <br /> <br />
年齡 : <s:property value="age"></s:property> <br /> <br />
地址 : <s:property value="address"></s:property> <br /> <br />
<hr>
<!-- 對于被我們改變的棧頂對象鸥鹉,我們可以用下標(biāo)的方式 -->
用戶名 : <s:property value="[1].username"></s:property> <br /> <br />
地址 : <s:property value="[1].address"></s:property> <br /> <br />
<hr>
<!-- 另外兩種方式 object['filedName'] 或者 object["filedName"] -->
用戶名 : <s:property value="[1]['username']"></s:property> <br /> <br />
地址 : <s:property value="[1]['address']"></s:property> <br /> <br />
  1. 讀取 Context Map 里的對象的屬性
    • 如果希望從map棧中查找屬性,只需要在表達(dá)式的開頭加個#
    • 例如:我們要從session域中查找一個屬性 #session.hello
<%
    session.setAttribute("hello", "你好");
    application.setAttribute("key", "appKey");
    session.setAttribute("key", "sessKey");
    request.setAttribute("key", "reqKey");
%>
<hr><br><br>
<!-- Map棧中Session數(shù)據(jù) -->
獲取到Session域中屬性: <s:property value="#session.hello"></s:property><br><br>
獲取請求參數(shù): <s:property value="#parameters.username"></s:property><br><br>
<!-- attr 會從小到大的范圍去查找 -->
通過attr獲取屬性值:<s:property value="#attr.key"/>
  • OGNL 調(diào)用字段和方法
    • 可以利用 OGNL 調(diào)用
      • 任何一個 Java 類里的靜態(tài)字段或方法.
      • 被壓入到 ValueStack 棧的對象上的公共字段和方法.
    • 首先對于靜態(tài)方法的調(diào)用庶骄,我們需要在 struts.xml 文件中開啟
<!-- 開啟靜態(tài)方法訪問 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
  • 調(diào)用靜態(tài)字段或方法需要使用如下所示的語法:
    • @fullyQualifiedClassName@fieldName: @java.util.Calendar@DECEMBER
    • @fullyQualifiedClassName@methodName(argumentList): @app4.Util@now()
<!-- 調(diào)用靜態(tài)方法和字段 -->
調(diào)用靜態(tài)字段: <s:property value="@java.util.Calendar@WEEK_OF_YEAR"></s:property><br>
<!-- 對于調(diào)用靜態(tài)方法毁渗,我們需要去 struts.xml 文件中配置-->
調(diào)用靜態(tài)方法: <s:property value="@org.pan.struts2.entity.User@sayHello('張三豐')"></s:property>
  • 調(diào)用 ValueStack 棧的對象的 非靜態(tài)方法和字段公共字段和方法.)
<!-- 調(diào)用棧頂對象的 公共方法和屬性(屬性就是我們之前訪問的字段值) -->
調(diào)用公共方法: <s:property value="sayYou('巨無霸')"></s:property>
  • OGNL 獲取 數(shù)組、List单刁、Map 信息
  1. OGNL 訪問數(shù)組類型的屬性
    • 有些屬性將返回一個對象數(shù)組而不是單個對象, 可以像讀取任何其他對象屬性那樣讀取它們. 這種數(shù)組型屬性的各個元素以逗號分隔, 并且不帶方括號
    • 可以使用下標(biāo)訪問數(shù)組中指定的元素: colors[0]
    • 可以通過調(diào)用其 length 字段查出給定數(shù)組中有多少個元素: colors.length
<!-- OGNL 訪問數(shù)組類型的屬性 -->
<%
    String[] names = new String[]{"aa","bb","cc","dd"};
    request.setAttribute("names", names);
%>
length:<s:property value="#attr.names.length"/>
<br/>
names[1]:<s:property value="#attr.names[1]"/>
  1. OGNL 訪問 List 類型屬性
    • 有些屬性將返回的類型是 java.util.List, 可以像讀取任何其他屬性那樣讀取它們. 這種 List 的各個元素是字符串, 以逗號分隔, 并且?guī)Х嚼ㄌ?/li>
    • 可以使用下標(biāo)訪問 List 中指定的元素: colors[0]
    • 可以通過調(diào)用其 size 方法或?qū)S藐P(guān)鍵字 size 的方法查出給定List 的長度: colors.size 或 colors.size()
    • 可以通過使用 isEmpty() 方法或專用關(guān)鍵字 isEmpty 來得知給定的 List 是不是空. colors.isEmpty 或 colors.isEmpty()
    • 還可以使用 OGNL 表達(dá)式來創(chuàng)建 List, 創(chuàng)建一個 List 與聲明一個 Java 數(shù)組是相同的: {“Red”, “Black”, “Green”}
<%
    List<String> colors = new ArrayList<String>();
    colors.add("Red");
    colors.add("Black");
    colors.add("Green");
    request.setAttribute("colors", colors);
%>
isEmpty: <s:property value="#request.colors.isEmpty()"></s:property><br><br>
size: <s:property value="#request.colors.size"></s:property><br><br>
colors: <s:property value="#request.colors[1]"></s:property>
  1. OGNL 訪問Map 類型屬性
    • 讀取一個 Map 類型的屬性將以如下所示的格式返回它所有的鍵值對:
    • 若希望檢索出某個 Map 的值, 需要使用如下格式: map['key']
    • 可以使用 size 或 size() 得出某個給定的 Map 的鍵值對的個數(shù)
    • 可以使用 isEmpty 或 isEmpty() 檢查某給定 Map 是不是空.
    • 可以使用 #{key1:value1, key2:value2, key3:value3}的方式創(chuàng)建一個Map
<!-- OGNL 訪問Map類型屬性 -->
<%
    Map<String,String> letters = new HashMap<String,String>();
    letters.put("AA", "aa");
    letters.put("BB", "bb");
    letters.put("CC", "cc");
    request.setAttribute("letters", letters);
%>
isEmpty: <s:property value="#request.letters.isEmpty"></s:property><br><br>
size:<s:property value="#attr.letters.size()"/><br><br/>
AA:<s:property value="#attr.letters['AA']"/><br><br>
創(chuàng)建Map: <s:set var="testMap" value="#{'AA':'aa', 'BB':'bb', 'CC':'cc'}"></s:set><br><br>
讀取創(chuàng)建的Map: <s:property value="#attr.testMap.AA"></s:property>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灸异,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肺樟,老刑警劉巖檐春,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異儡嘶,居然都是意外死亡喇聊,警方通過查閱死者的電腦和手機(jī)恍风,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門蹦狂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人朋贬,你說我怎么就攤上這事凯楔。” “怎么了锦募?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵摆屯,是天一觀的道長。 經(jīng)常有香客問我糠亩,道長虐骑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任赎线,我火速辦了婚禮廷没,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘垂寥。我一直安慰自己颠黎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布滞项。 她就那樣靜靜地躺著狭归,像睡著了一般。 火紅的嫁衣襯著肌膚如雪文判。 梳的紋絲不亂的頭發(fā)上过椎,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機(jī)與錄音戏仓,去河邊找鬼疚宇。 笑死,一個胖子當(dāng)著我的面吹牛柜去,可吹牛的內(nèi)容都是我干的灰嫉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嗓奢,長吁一口氣:“原來是場噩夢啊……” “哼讼撒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤根盒,失蹤者是張志新(化名)和其女友劉穎钳幅,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炎滞,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡敢艰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了册赛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钠导。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖森瘪,靈堂內(nèi)的尸體忽然破棺而出牡属,到底是詐尸還是另有隱情,我是刑警寧澤扼睬,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布逮栅,位于F島的核電站,受9級特大地震影響窗宇,放射性物質(zhì)發(fā)生泄漏措伐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一军俊、第九天 我趴在偏房一處隱蔽的房頂上張望侥加。 院中可真熱鬧,春花似錦蝇完、人聲如沸官硝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氢架。三九已至,卻和暖如春朋魔,著一層夾襖步出監(jiān)牢的瞬間岖研,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工警检, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留孙援,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓扇雕,卻偏偏與公主長得像拓售,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子镶奉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

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

  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產(chǎn)品础淤,是在 struts1和WebWork的...
    inke閱讀 2,256評論 0 50
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法崭放,類相關(guān)的語法,內(nèi)部類的語法鸽凶,繼承相關(guān)的語法币砂,異常的語法,線程的語...
    子非魚_t_閱讀 31,632評論 18 399
  • 1玻侥、struts2工作流程 Struts 2框架本身大致可以分為3個部分: 核心控制器FilterDispatch...
    重山楊閱讀 1,520評論 0 38
  • 標(biāo)簽 如果要配置的標(biāo)簽决摧,那么必須要先配置標(biāo)簽,代表的包的概念凑兰。 包含的屬性 name包的名稱掌桩,要求是唯一的,管理a...
    偷偷得路過閱讀 1,344評論 0 0
  • 二票摇、 我被接近皇宮的第二天拘鞋,王子便告訴我我們會結(jié)婚的喜訊。我?guī)缀趼錅I矢门,我的愛人啊灰蛙!你是國家的王子祟剔,更是我的王子啊摩梧!...
    Sikooooo閱讀 367評論 0 0