Struts2中的OGNL詳解

1、OGNL的概念

OGNL是Object-Graph Navigation Language的縮寫,全稱爲對象圖導航語言,是一種功能強大的表達式語言,它經過簡單一致的語法,能夠任意存取對象的屬性或者調用對象的方法,可以遍歷整個對象的結構圖,實現對象屬性類型的轉換等功能。javascript

 

2、OGNL的基礎知識:

1. OGNL表達式的計算是圍繞OGNL上下文進行的
OGNL上下文實際上就是一個Map對象,由ognl.OgnlContext類表示。它裏面能夠存放不少個JavaBean對象。它有一個上下文根對象。
上下文中的根對象能夠直接使用名來訪問或直接使用它的屬性名訪問它的屬性值。不然要加前綴「#key」。 
2. Struts2的標籤庫都是使用OGNL表達式來訪問ActionContext中的對象數據的。如:<s:propertyvalue="xxx"/>
3. Struts2將ActionContext設置爲OGNL上下文,並將值棧做爲OGNL的根對象放置到ActionContext中
4. 值棧(ValueStack)
能夠在值棧中放入、刪除、查詢對象。訪問值棧中的對象不用「#」。
Struts2老是把當前Action實例放置在棧頂。因此在OGNL中引用Action中的屬性也能夠省略「#」。
5. 調用ActionContext的put(key,value)放入的數據,須要使用#訪問
 

3、OGNL中重要的3個符號:#、%、$:

#、%和$符號在OGNL表達式中常常出現,而這三種符號也是開發者不容易掌握和理解的部分,須要時間的積累才漸漸弄清楚……
1.#符號

#符號的用途通常有三種:html

A、訪問非根對象屬性,例如#session.msg表達式,因爲Struts 2中值棧被視爲根對象,因此訪問其餘非根對象時,須要加#前綴。實際上,#至關於ActionContext. getContext();#session.msg表達式至關於ActionContext.getContext().getSession(). getAttribute("msg") 。java

B、用於過濾和投影(projecting)集合,如persons.{?#this.age>25},persons.{?#this.name=='pla1'}.{age}[0]。spring

C、用來構造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。apache

2.%符號

「%」符號的用途是在標籤的屬性值被理解爲字符串類型時,告訴執行環境%{}裏的是OGNL表達式。 實際上就是讓被理解爲字符串的表達式,被真正當成ognl來執行。頗有點相似javascript裏面的eval_r()功能。
另外用%{}能夠取出存在值堆棧中的Action對象,直接調用它的方法,例如你的Action若是繼承了ActionSupport .那麼在頁面標籤中,用%{getText('key')}的方式能夠拿出國際化信息.

3.$符號

$符號主要有兩個方面的用途。數組

A、在國際化資源文件中,引用OGNL表達式,例如國際化資源文件中的代碼:reg.agerange=國際化資源信息:年齡必須在${min}同${max}之間。session

B、在Struts 2框架的配置文件中引用OGNL表達式,例如:app

<validators>  
    <field name="intb">  
            <field-validator type="int">  
            <param name="min">10</param>  
            <param name="max">100</param>  
            <message>BAction-test校驗:數字必須爲${min}爲${max}之間!</message>  
        </field-validator>  
    </field>  
</validators> 

 

4、OGNL代碼示例

action類OgnlAction.java:
package com.tjcyjd.test.action;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.springframework.stereotype.Controller;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

@Controller
@Namespace("/test")
@ParentPackage("struts-default")
@Results( { @Result(name = "success", location = "/other_test/showognl.jsp"),
        @Result(name = "fail", location = "/bbs/admin_login.jsp"),
        @Result(name = "input", location = "/bbs/admin_login.jsp") })
public class OgnlAction extends ActionSupport {
    private static final long serialVersionUID = -1494290883433357310L;
    private List<Person> persons;

    @Action("ognlTest")
    public String ognlTest() throws Exception {
        // 得到ActionContext實例,以便訪問Servlet API
        ActionContext ctx = ActionContext.getContext();
        // 存入application
        ctx.getApplication().put("msg", "application信息");
        // 保存session
        ctx.getSession().put("msg", "seesion信息");
        // 保存request信息
        HttpServletRequest request = ServletActionContext.getRequest();
        request.setAttribute("msg", "request信息");
        // 爲persons賦值
        persons = new LinkedList<Person>();
        Person person1 = new Person();
        person1.setName("pla1");
        person1.setAge(26);
        person1.setBirthday(new Date());
        persons.add(person1);

        Person person2 = new Person();
        person2.setName("pla2");
        person2.setAge(36);
        person2.setBirthday(new Date());
        persons.add(person2);

        Person person3 = new Person();
        person3.setName("pla3");
        person3.setAge(16);
        person3.setBirthday(new Date());
        persons.add(person3);

        return SUCCESS;

    }

    public List<Person> getPersons() {
        return persons;
    }

    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }
}

 

jsp頁面showognl.jsp:框架

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/ xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Struts2 OGNL 演示</title>
</head>
<body>
    <h3>訪問OGNL上下文和Action上下文</h3>
    <!-使用OGNL訪問屬性值-->
    <p>parameters: <s:property value="#parameters.msg" /> (\${param.msg}: ${param.msg})</p>
    <p>request.msg: <s:property value="#request['msg']" /></p>
    <p>session.msg: <s:property value="#session.msg" /></p>
    <p>application.msg: <s:property value="#application.msg" /></p>
    <p>attr.msg: <s:property value="#attr.msg" /></p>
    <hr />
    
    <h3>用於過濾和投影(projecting)集合</h3>
    <p>年齡大於20</p>
    <ul>
    <!-判斷年齡-->
        <s:iterator value="persons.{?#this.age>20}">
            <li><s:property value="name" /> - 年齡:<s:property value="age" /></li>
        </s:iterator>
    </ul>
    <p>姓名爲pla1的年齡: <s:property value="persons.{?#this.name=='pla1'}.{age}[0]"/></p>
    <hr />
    
    <h3>構造Map</h3>
    <s:set var="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
    <p>The value of key "foo1" is <s:property value="#foobar['foo1']" /></p>
      <hr />
      
      <h4>%符號的用法</h4>
    <s:set var="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
    <p>The value of key "foo1" is <s:property value="#foobar['foo1']" /></p>
    <p>不使用%:<s:url value="#foobar['foo1']" /></p>
    <p>使用%:<s:url value="%{#foobar['foo1']}" /></p>
      <hr />
    <%
         request.setAttribute("req", "request scope");
         request.getSession().setAttribute("sess", "session scope");
         request.getSession().getServletContext().setAttribute("app",
                 "aplication scope");
     %>
     
        1.經過ognl表達式獲取 屬性範圍中的值
     <br>
     <s:property value="#request.req" />
     <br />
     <s:property value="#session.sess" />
     <br />
     <s:property value="#application.app" />
     <br />
     <hr>
     
    2.經過<span style="background-color: #fafafa;">ognl表達式建立list 集合 ,而且遍歷出集合中的值</span>
     <br>
     <s:set var="list" value="{'eeeee','ddddd','ccccc','bbbbb','aaaaa'}"></s:set>
     <s:iterator value="#list" var="o">
         <!-- ${o }<br/> -->
         <s:property />
         <br />
     </s:iterator>
     <br />
     <hr>
     
    3.經過ognl表達式建立Map 集合 ,而且遍歷出集合中的值
     <br>
     <s:set var="map" value="#{'1':'eeeee','2':'ddddd','3':'ccccc','4':'bbbbb','5':'aaaaa'}" />
     <s:iterator value="#map" var="o" status="s">
         <!--      ${o.key }->${o.value }  index:${s.index}<br/>   -->
         <!-- <s:property value="#o.key"/>-><s:property value="#o.value"/><br/>   -->
         <s:property value="key" />-><s:property value="value" />
         <br />
     </s:iterator>
     <br />
     <hr>
     
   4.經過ognl表達式 進行邏輯判斷
     <br>
     <s:if test="'aa' in {'aaa','bbb'}">
         aa 在 集合{'aaa','bbb'}中;
     </s:if>
     <s:else>
         aa 不在 集合{'aaa','bbb'}中;
     </s:else>
     <br />
     <s:if test="#request.req not in #list">
             不 在 集合list中;
     </s:if>
     <s:else>
             在 集合list中;
     </s:else>
     <br />
     <hr>
     
    5.經過ognl表達式 的投影功能進行數據篩選
     <br>
     <s:set var="list1" value="{1,2,3,4,5}"></s:set>
     <s:iterator value="#list1.{?#this>2}" var="o">
         <!-- #list.{?#this>2}:在list1集合迭代的時候,從中篩選出當前迭代對象>2的集合進行顯示 -->
         ${o }<br />
     </s:iterator>
     <br />
     <hr>
     
    6.經過ognl表達式 訪問某個類的靜態方法和值
     <br>
     <s:property value="@java.lang.Math@floor(32.56)" />
     <s:property value="@com.rao.struts2.action.OGNL1Action@aa" />
     <br />
     <br />
     <hr>
   7.ognl表達式 迭代標籤 詳細
     <br>
     <s:set var="list2"
         value="{'aa','bb','cc','dd','cee','ff','gg','hh','ii','jj'}"></s:set>
     <table border="1">
         <tr>
             <td>索引 </td>
             <td>值</td>
             <td>奇?</td>
             <td> 偶?</td>
             <td>首?</td>
             <td> 尾?</td>
             <td>當前迭代數量</td>
         </tr>
         <s:iterator value="#list2.{?#this.startsWith('c')}" var="o" status="s">
             <tr bgcolor="<s:if test="#s.even">pink</s:if>">
                 <td>
                     <s:property value="#s.index" />
                 </td>
                 <td>
                     <s:property />  (\${o}:${o})
                 </td>
                 <td>
                     <s:if test="#s.odd">Y</s:if>
                     <s:else>N</s:else>
                 </td>
                 <td>
                     <s:if test="#s.even">Y</s:if>
                     <s:else>N</s:else>
                 </td>
                 <td>
                     <s:if test="#s.first">Y</s:if>
                     <s:else>N</s:else>
                 </td>
                 <td>
                     <s:if test="#s.last">Y</s:if>
                     <s:else>N</s:else>
                 </td>
                 <td>
                 <s:property value="#s.count"/>
             </td>
             </tr>
         </s:iterator>
     </table>
     <br>
     <hr>
     
    8.ognl表達式:  if/else if/else 詳細<br>
     <% request.setAttribute("aa",0); %>
     <s:if test="#request.aa>=0 && #request.aa<=4">
             在0-4之間;
     </s:if>
     <s:elseif test="#request.aa>=4 && #request.aa<=8">
             在4-8之間;
     </s:elseif>
     <s:else>
             大於8;
     </s:else>
     <br>
     <hr>
     
 9.ognl表達式: url 詳細<br>
     <% request.setAttribute("aa","sss"); %>
     <s:url action="testAction" namespace="/aa/bb" var="myurls" escapeAmp="false">
         <s:param name="aa" value="#request.aa"></s:param>
         <s:param name="bb" value="#parameters.bb"></s:param>
         <s:param name="id">100</s:param>
         <s:param name="name">謝春平</s:param>
     </s:url>
     
      <s:url value="%{#myurls}"></s:url> <br/><!-- 注意此時會再次加入contextPath,同時編碼& -->
       ${myurls}<br/>
      <a href="<s:property value="#myurls" />" >測試</a></a><br/><!-- 注意此時會再次對&編碼 -->
     <br/>
     <s:set var="myurl" value="'http://www.baidu.com'"></s:set>
     value以字符處理:   <s:url value="#myurl" action="asss"></s:url><br><!-- 同時出現,使用value -->
     value明確指定以ognl表達式處理:    <s:url value="%{#myurl}"></s:url>
     <br>
     <hr>
     
 10.ognl表達式: checkboxlist 詳細<br>
     1> .list 生成;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
     name:checkboxlist的名字<br>
     list:checkboxlist要顯示的列表<br>
     value:checkboxlist默認被選中的選項,checked=checked<br>
     <s:checkboxlist name="checkbox1" list="{'上網','看書','登山','游泳','唱歌'}" value="{'上網','看書'}" ></s:checkboxlist>
     <br>
         以上生成代碼:<br>
     <xmp>
         <input type="checkbox" name="checkbox1" value="上網" id="checkbox1-1" checked="checked"/>
         <label for="checkbox1-1" class="checkboxLabel">上網</label>
         <input type="checkbox" name="checkbox1" value="看書" id="checkbox1-2" checked="checked"/>
         <label for="checkbox1-2" class="checkboxLabel">看書</label>
         <input type="checkbox" name="checkbox1" value="登山" id="checkbox1-3"/>
         <label for="checkbox1-3" class="checkboxLabel">登山</label>
         <input type="checkbox" name="checkbox1" value="游泳" id="checkbox1-4"/>
         <label for="checkbox1-4" class="checkboxLabel">游泳</label>
         <input type="checkbox" name="checkbox1" value="唱歌" id="checkbox1-5"/>
         <label for="checkbox1-5" class="checkboxLabel">唱歌</label>"
     </xmp>
     2> .Map 生成;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
     name:checkboxlist的名字<br>
     list:checkboxlist要顯示的列表<br>
     listKey:checkbox 的value的值<br>
     listValue:checkbox 的lablel(顯示的值)<br>
     value:checkboxlist默認被選中的選項,checked=checked<br>
     <s:checkboxlist name="checkbox2" list="#{1:'上網',2:'看書',3:'登山',4:'游泳',5:'唱歌'}" listKey="key" listValue="value" value="{1,2,5}" ></s:checkboxlist>
     <br>
        以上生成代碼:<br>
     <xmp>
         <input type="checkbox" name="checkbox2" value="1" id="checkbox2-1" checked="checked"/>
         <label for="checkbox2-1" class="checkboxLabel">上網</label>
         <input type="checkbox" name="checkbox2" value="2" id="checkbox2-2" checked="checked"/>
         <label for="checkbox2-2" class="checkboxLabel">看書</label>
         <input type="checkbox" name="checkbox2" value="3" id="checkbox2-3"/>
         <label for="checkbox2-3" class="checkboxLabel">登山</label>
         <input type="checkbox" name="checkbox2" value="4" id="checkbox2-4"/>
         <label for="checkbox2-4" class="checkboxLabel">游泳</label>
         <input type="checkbox" name="checkbox2" value="5" id="checkbox2-5" checked="checked"/>
         <label for="checkbox2-5" class="checkboxLabel">唱歌</label>
     </xmp>
     <hr>
</body>
</html>

 

5、總結OGNL的使用方法

一、訪問屬性
名字屬性獲取: <s:property value="user.username"/><br>jsp

地址屬性獲取: <s:property value="user.address.addr"/><br>

 

二、訪問方法
調用值棧中對象的普通方法:<s:property value="user.get()"/><br>

 

三、訪問靜態屬性和方法
調用Action中的靜態方法:<s:property value="@struts.action.LoginAction@get()"/>

調用JDK中的類的靜態方法:<s:property value="@java.lang.Math@floor(44.56)"/><br>

調用JDK中的類的靜態方法(同上):<s:property value="@@floor(44.56)"/><br>

調用JDK中的類的靜態方法:<s:property value="@java.util.Calendar@getInstance()"/><br>

調用普通類中的靜態屬性:<s:property value="@struts.vo.Address@TIPS"/><br>

 

四、訪問構造方法
調用普通類的構造方法:<s:property value="new struts.vo.Student('李曉紅' , '美女' , 3 , 25).username"/>

 

五、訪問數組
獲取List:<s:property value="testList"/>

獲取List中的某一個元素(可使用相似於數組中的下標獲取List中的內容): <s:property value="testList[0]"/>

獲取Set:<s:property value="testSet"/>

獲取Set中的某一個元素(Set因爲沒有順序,因此不能使用下標獲取數據):<s:property value="testSet[0]"/>

獲取Map:<s:property value="testMap"/>

獲取Map中全部的鍵:<s:property value="testMap.keys"/>

獲取Map中全部的值:<s:property value="testMap.values"/>

獲取Map中的某一個元素(可使用相似於數組中的下標獲取List中的內容):<s:property value="testMap['m1']"/>

獲取List的大小:<s:property value="testSet.size"/>

 

六、訪問集合 – 投影、選擇(? ^ $)
利用選擇獲取List中成績及格的對象:<s:property value="stus.{?#this.grade>=60}"/>

利用選擇獲取List中成績及格的對象的username:<s:property value="stus.{?#this.grade>=60}.{username}"/>

利用選擇獲取List中成績及格的第一個對象的username:<s:property value="stus.{?#this.grade>=60}.{username}[0]"/>

利用選擇獲取List中成績及格的第一個對象的username:<s:property value="stus.{^#this.grade>=60}.{username}"/>

利用選擇獲取List中成績及格的最後一個對象的username:<s:property value="stus.{$#this.grade>=60}.{username}"/>

利用選擇獲取List中成績及格的第一個對象而後求大小:<s:property value="stus.{^#this.grade>=600}.{username}.size"/>

 

七、集合的僞屬性
OGNL可以引用集合的一些特殊的屬性,這些屬性並非JavaBeans模式,例如size(),length()等等. 當表達式引用這些屬性時,OGNL會調用相應的方法,這就是僞屬性.

集合

僞屬性

Collection(inherited by Map, List & Set)

size ,isEmpty

List

iterator

Map

keys , values

Set

iterator

Iterator

next , hasNext

Enumeration

next , hasNext , nextElement , hasMoreElements

 

八、Lambda :[…]
格式::[…]

使用Lambda表達式計算階乘:<s:property value="#f = :[#this==1?1:#this*#f(#this-1)] , #f(4)"/>

 

九、OGNL中#的使用
#能夠取出堆棧上下文中的存放的對象.

名稱

做用

例子

parameters

包含當前HTTP請求參數的Map

#parameters.id[0]做用至關於

request.getParameter("id")

request

包含當前HttpServletRequest的屬性(attribute)的Map

#request.userName至關於

request.getAttribute("userName")

session

包含當前HttpSession的屬性(attribute)的Map

#session.userName至關於

session.getAttribute("userName")

application

包含當前應用的ServletContext的屬性(attribute)的Map

#application.userName至關於

application.getAttribute("userName")

attr

用於按request > session > application順序訪問其屬性(attribute)

 

獲取Paraments對象的屬性:<s:property value="#parameters.username"/>

 

十、OGNL中%的使用
用%{}能夠取出存在值堆棧中的Action對象,直接調用它的方法.

例如你的Action若是繼承了ActionSupport .那麼在頁面標籤中,用%{getText('key')}的方式能夠拿出國際化信息.

 

十一、OGNL中$的使用

「$」有兩個主要的用途:
A、用於在國際化資源文件中,引用OGNL表達式
B、在Struts 2配置文件中,引用OGNL表達式

 

十二、值棧
ValueStack對象。這個對象貫穿整個Action的生命週期(每一個Action類的對象實例會擁有一個ValueStack對象)。當Struts 2接收到一個.action的請求後,會先創建Action類的對象實例,但並不會調用Action方法,而是先將Action類的相應屬性放到ValueStack對象的頂層節點(ValueStack對象至關於一個棧)。

在Action中得到ValueStack對象:ActionContext.getContext().getValueStack()

A、Top語法
使用Top獲取值棧中的第二個對象:<s:property value="[1].top.對象"/>

B、N語法
使用N獲取值棧中的第二個對象:<s:property value="[1].對象"/>

C、@語法
調用action中的靜態方法:<s:property value="@vs1@靜態方法"/> vs:值棧 1:表示第一個。

 

1三、OGNL表達式和struts標籤的整合使用,及OGNL表達式的技術要點

使用OGNL表達式獲取
* appliaction : #appliaction.username 或者 #application['username'] ,至關於appliaction.getAttribute("username");
* session : #session.username 或者 #session['username'],至關於session。getAttribute("username");
* request : #request.username 或者 #request['username'],至關於request.getAttribute("username");
* parameters: #parameters.username 或者 #parameters['username'],至關於 request.getParameter("username")
* attr : 按照pageContext--->request---->session--->application 順序訪問屬性
使用OGNL動態獲取值:
* 若是是屬性: 直接寫屬性的名字
* 若是是變量: 須要在變量的名字加個 # 的前綴。
關於struts2標籤和OGNL的幾個注意事項:
* struts2 標籤都支持動態數據訪問,標籤的屬性均可使用ONGL表達式。struts 2 標籤的屬性都具備類型,
* 能夠簡單的分爲兩類:字符串類型和對象類型。<s:url>爲字符串 ,<s:set> <s:property>爲Object類型
* 對於字符串的屬性,若是要訪問動態數據,必須使用 %{...} 這樣的語法,不然直接當作字符串常量。
* 對於Object的屬性,將直接當作OGNL表達式求解,若是須要對對象類型的屬性指定字符串常量,則必須在這個字符串常量外加上一對單引號或者%{'constant String'}這樣的語法
* 若是對對象的屬性使用了%{....}的語法,則語法會被忽略,而直接把內容當中OGNL 表達式求解。eg:<s:property value="%{#myurl}" /> 和<s:property value="#url" />做用是相同的。

* 經驗:若是分不清一個屬性的值的類型是否是字符串類型的,能夠直接加上%{....}

 

1四、OGNL 表達式 和 EL 表達式的區別: * 在struts2 中,OGNL表達式必須和struts2標籤配合使用,而不能單獨使用,而EL表達式能夠單獨使用,不能和struts2標籤配合使用。 * ActionContext 是struts2 中 OGNL 表達式的上下文,該上下文中有多個Map對象,eg:application , session等,包括ValueStack 。可是ValueStack是跟對象,能夠直接訪問,其餘對象訪問須要加 # 前綴。

相關文章
相關標籤/搜索