Struts2【OGNL、valueStack】就是這麼簡單

什麼是OGNL表達式?

OGNL是Object Graphic Navigation Language 是操做對象屬性的開源表達式。 Struts2框架使用OGNL做爲默認的表達式語言。html

爲何咱們學習OGNL

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

  • 支持對象方法調用,如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表達式是怎麼取出數據的session

valueStack也被稱做值棧對象..app

  • 當用戶訪問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結構...spa

public class OgnlContext implements Map {}

複製代碼

小總結

這裏寫圖片描述

CompoundRoot保存着這樣的數據:debug

  • 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/>1、.構建 list集合</br>
    <s:iterator var="str" value="{'a','b'}">
    	<s:property value="#str"/>
    </s:iterator>
    
     <br/>1、.構建 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>
複製代碼

若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y

相關文章
相關標籤/搜索