Struts2第九篇【OGNL、valueStack詳解】

weixin_34377065發表於2018-01-21

tags: Struts2


什麼是OGNL表示式?

OGNL是Object Graphic Navigation Language 是操作物件屬性的開源表示式。 Struts2框架使用OGNL作為預設的表示式語言。

為什麼我們學習OGNL

在學習JSP的時候,我們已經學習過了EL表示式。EL表示式用起來也十分簡單...我們在Struts2框架中也是可以使用EL表示式的...那麼OGNL表示式好在哪裡呢??

  • 支援物件方法呼叫,如xxx.doSomeSpecial()
  • 支援類靜態的方法呼叫和值訪問,表示式的格式【例如:"@@floor(10.9)"就是呼叫Math.floor()的方法了】
  • 支援賦值操作和表示式串聯【這個其實EL表示式也能做】
  • 訪問OGNL上下文(OGNL context)和ActionContext
  • 操作集合物件【EL只能遍歷集合,OGNL可以建立集合】

OGNL是Struts2的預設表示式語言,OGNL是配搭Strut2的標籤使用的..我們學習了OGNL表示式,就可以更好地理解Struts2標籤的執行以及Struts2內部的儲存結構.

valueStack物件

在講解OGNL表示式之前,我們先來看看valueStack物件...valueStack是Struts2資料儲存的核心...我們首先要知道資料是怎麼存的,存到哪裡,然後才講解OGNL表示式是怎麼取出資料的

valueStack也被稱作值棧物件..

  • 當使用者訪問Action,都會建立一個Action物件,ActionContext物件、valueStack物件..
  • Struts2把Action物件放進valueStack物件之中
  • 將valueStack放進request域中,傳入JSP頁面(key: struts.valueStack)
  • JSP頁面就可以使用OGNL表示式獲取值棧中的資料了

獲取valueStack物件

  • 在Action中我們可以手動獲取值棧物件,有兩種方式獲取
	//獲取值棧物件的2種方式
	private void getVs() {
		// 獲取值棧物件,方式1:
		HttpServletRequest request = ServletActionContext.getRequest();
		ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");
		
		// 獲取值棧物件,方式2: 
		ActionContext ac = ActionContext.getContext();
		ValueStack vs2 = ac.getValueStack();
		
		System.out.println(vs1 == vs2);//true
	}
	
複製程式碼

valueStack內部儲存結構

上面已經說了,使用者訪問Action時,會建立Action物件,valueStack物件。Struts2內部會將Action物件存到valueStack物件之中...那麼valueStack的儲存結構是什麼樣的呢???我們來看看

CompoundRoot

Action物件和Action的成員屬性等值都是存到CompoundRoot下的.該CompoundRoot繼承著ArrayList,因此它是List結構的

	public class CompoundRoot extends ArrayList {}

複製程式碼

OgnlContext

OgnlContext物件儲存著相關的域物件:request、response、session等資料,實現Map集合,是Map結構..

為了讓request、response等域物件可以儲存多個值,值也是使用Map結構...

public class OgnlContext implements Map {}

複製程式碼

小總結

CompoundRoot儲存著這樣的資料:

  • Action物件以及Action物件的成員屬性資料
  • 使用ValueStack物件.push()進去的資料
  • 使用ValueStack物件.set()進去的資料
  • 其他代理物件的資料

OgnlContext儲存著這樣的資料:

  • 維護了CompoundRoot中所有的資料
  • request、response等域物件所有的資料

OGNL表示式取值

  • Struts2會將valueStack物件封裝進request物件域中,傳入JSP頁面。
  • valueStack儲存著OgnlContext物件。
  • OgnlContext物件維護了CompoundRoot物件的資料
  • CompoundRoot儲存著Action等資料

也就是說通過OgnlContext物件可以獲取大部分我們需要的資料了。

那麼OGNL表示式是怎麼取出OgnlContext物件中資料的呢??下面我們通過硬編碼的方式來講解

	/**
	 * 1. Ognl表示式語言語言取值,取非根元素的值,必須用#號
	 * @throws Exception
	 */
	@Test
	public void testOgnl() throws Exception {
		// 建立一個Ognl上下文物件
		OgnlContext context = new OgnlContext();
		// 放入資料
		User user = new User();
		user.setId(100);
		user.setName("Jack");
		// 【往非根元素放入資料, 取值的時候表示式要用"#"】
		context.put("user", user);
		
		// 獲取資料(map)
		// 先構建一個Ognl表示式, 再解析表示式
		Object ognl = Ognl.parseExpression("#user.name");
		Object value = Ognl.getValue(ognl, context, context.getRoot());
		
		System.out.println(value);
	}
	
	/**
	 * 2. Ognl表示式語言語言取值,取根元素的值,不用帶#號
	 * @throws Exception
	 */
	@Test
	public void testOgn2() throws Exception {
		// 建立一個Ognl上下文物件
		OgnlContext context = new OgnlContext();
		// 放入資料
		User user = new User();
		user.setId(100);
		user.setName("Jack");
		// 【往根元素放入資料】
		context.setRoot(user);
		
		// 獲取資料(map)
		// 先構建一個Ognl表示式, 再解析表示式
		Object ognl = Ognl.parseExpression("address.province");
		Object value = Ognl.getValue(ognl, context, context.getRoot());
		
		System.out.println(value);
	}
	
複製程式碼

也就是說,JSP頁面中取出資料的時候,它會先構建一個OGNL表示式,再解析表示式

  • 如果是CompoundRoot類的資料,表示式不需要帶#號
  • 如果不是CompoundRoot類的資料,表示式需要帶#號

例子:



  	<!-- 頁面: 必須要拿到ValueStack -->
     <br/>1. 取根元素的值<br/>
     <s:property value="user.id"/> 
     <s:property value="user.name"/> 
     <s:property value="user.address"/> 
     <s:property value="user.address.city"/> 
     <s:property value="user.address.province"/> 
     
      <br/>2. 取非根元素的值<br/>
      <s:property value="#request.cn"/>
      <s:property value="#session.Session_data"/>
      <s:property value="#application.Application_data"/>    <br/>
     
      <!-- 自動找request/session/application,找到後立刻返回 -->
      <s:property value="#request_data"/>
      <s:property value="#attr.Session_data"/>
      <s:property value="#attr.Application_data"/>  <br/>
      
      <!-- 獲取請求的引數資料 -->
      <s:property value="#parameters.userName"/>
     
     <!-- struts的除錯標籤:可以觀測值棧資料 -->
     <s:debug></s:debug>

複製程式碼

OGNL對靜態方法的呼叫


	/**
	 * 3.Ognl對 靜態方法呼叫的支援
	 * @throws Exception
	 */
	@Test
	public void testOgn3() throws Exception {
		// 建立一個Ognl上下文物件
		OgnlContext context = new OgnlContext();
		
		// Ognl表單式語言,呼叫類的靜態方法
		//Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
		// 由於Math類在開發中比較常用,所以也可以這樣寫
		Object ognl = Ognl.parseExpression("@@floor(10.9)");
		Object value = Ognl.getValue(ognl, context, context.getRoot());
		System.out.println(value);
	}
複製程式碼

OGNL建立集合


    <br/>一、.構建 list集合</br>
    <s:iterator var="str" value="{'a','b'}">
    	<s:property value="#str"/>
    </s:iterator>
    
     <br/>一、.構建 map集合</br>
     <s:iterator var="en" value="#{'cn':'China','usa':'America'}">
     	<s:property value="#en.key"/>
     	<s:property value="#en.value"/>  <br/>
     </s:iterator>

複製程式碼

構建Map集合的時候,需要使用#號


#OGNL 幾個特殊的符號#

#獲取非根元素值 、 動態都建map集合 $ 在配置檔案取值 % 提供一個ognl表示式執行環境


<body>
  	 <br/>獲取request域資料<br/>
  	 <!-- property 標籤是物件型別的標籤,預設支援ognl表示式, 會從根元素去China名稱對應的值 -->
  	 <s:property value="China"/>		<br/>
  	 <!-- 如果直接賦值,需要用單引號 -->
  	 <s:property value="'China'"/>		<br/>
  	 <s:property value="%{#request.cn}"/>		<br/>
  	 
  	 <!-- 值型別的標籤,value值預設就是值型別,不支援ognl表示式 -->
  	 國家:<s:textfield name="txtCountry" value="%{#request.cn}"></s:textfield>
  </body>
複製程式碼

如果您覺得這篇文章幫助到了您,可以給作者一點鼓勵

相關文章