OGNL表達式介紹


OGNL是Object-Graph Navigation Language的縮寫,它是一種功能強大的表達式語言(Expression Language,簡稱為EL),通過它簡單一致的表達式語法,可以存取對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。它使用相同的表達式去存取對象的屬性。                -------百度百科

從語言角度來說:它是一個功能強大的表達式語言,用來獲取和設置 java 對象的屬性 ,它旨在提供一個更高抽象度語法來對 java 對象圖進行導航。另外,java 中很多可以做的事情,也可以使用 OGNL 來完成,例如:列表映射和選擇。對於開發者來說,使用 OGNL,可以用簡潔的語法來完成對 java 對象的導航。通常來說:通過一個“路徑”來完成對象信息的導航,這個“路徑”可以是到 java bean 的某個屬性,或者集合中的某個索引的對象,等等,而不是直接使用 get 或者 set 方法來完成。

  首先來介紹下OGNL的三要素:

  一、表達式:

    表達式(Expression)是整個OGNL的核心內容,所有的OGNL操作都是針對表達式解析后進行的。通過表達式來告訴OGNL操作到底要干些什么。因此,表達式其實是一個帶有語法含義的字符串,整個字符串將規定操作的類型和內容。OGNL表達式支持大量的表達式,如“鏈式訪問對象”、表達式計算、甚至還支持Lambda表達式。

  二、Root對象:

    OGNL的Root對象可以理解為OGNL的操作對象。當我們指定了一個表達式的時候,我們需要指定這個表達式針對的是哪個具體的對象。而這個具體的對象就是Root對象,這就意味着,如果有一個OGNL表達式,那么我們需要針對Root對象來進行OGNL表達式的計算並且返回結果。

  三、上下文環境:

    有個Root對象和表達式,我們就可以使用OGNL進行簡單的操作了,如對Root對象的賦值與取值操作。但是,實際上在OGNL的內部,所有的操作都會在一個特定的數據環境中運行。這個數據環境就是上下文環境(Context)。OGNL的上下文環境是一個Map結構,稱之為OgnlContext。Root對象也會被添加到上下文環境當中去。

  OGNL 的基本語法:

  1. 對Root對象的訪問

  OGNL使用的是一種鏈式的風格進行對象的訪問。具體代碼如下:

@Test
    public void testOgnl()
    {
        User user = new User("rcx", "123");
        Address address = new Address("110003", "沈陽市和平區");
        user.setAddress(address);
        try
        {
            System.out.println(Ognl.getValue("name", user));
            System.out.println(Ognl.getValue("address", user));
            System.out.println(Ognl.getValue("address.port", user));

            //輸出結果:
         //rcx
           //com.rcx.ognl.Address@dda25b
           //110003
        }
        catch (OgnlException e)
        {
            e.printStackTrace();
        }
    }

 2. 對上下文對象的訪問

  使用OGNL的時候如果不設置上下文對象,系統會自動創建一個上下文對象,如果傳入的參數當中包含了上下文對象則會使用傳入的上下文對象。當訪問上下文環境當中的參數時候,需要在表達式前面加上'#',表示了與訪問Root對象的區別。具體代碼如下:

@Test
    public void testOgnl1()
    {
        User user = new User("rcx", "123");
        Address address = new Address("110003", "沈陽市和平區");
        user.setAddress(address);
        Map<String, Object> context = new HashMap<String, Object>();
        context.put("init", "hello");
        context.put("user", user);
        try
        {
            System.out.println(Ognl.getValue("#init", context, user));
            System.out.println(Ognl.getValue("#user.name", context, user));
            System.out.println(Ognl.getValue("name", context, user));
            //輸出結果:
          //hello
            //rcx
            //rcx       
         }
        catch (OgnlException e)
        {
            e.printStackTrace();
        }
    }

 這段代碼很好的區分了訪問Root對象和訪問上下文對象的區別。

  3. 對靜態變量的訪問

  在OGNL表達式當中也可以訪問靜態變量或者調用靜態方法,格式如@[class]@[field/method()]。具體代碼如下:

public class Constant
{
    public final static String ONE = "one";
    
    public static void get()
    {}
    
    public static String getString()
    {
        return "string";
    }
}

    @Test
    public void testOgnl2()
    {
        try
        {
            Object object = Ognl.getValue("@com.rcx.ognl.Constant@ONE", null);
            
            Object object1 = Ognl.getValue("@com.rcx.ognl.Constant@get()", null);
            
            Object object2 = Ognl.getValue("@com.rcx.ognl.Constant@getString()", null);
            
            System.out.println(object);
            System.out.println(object1);
            System.out.println(object2);
            //one
            //null 當返回值是void的時候輸出的是null
            //string
        }
        catch (OgnlException e)
        {
            e.printStackTrace();
        }
    }

  4. 方法的調用

  如果需要調用Root對象或者上下文對象當中的方法也可以使用.+方法的方式來調用。甚至可以傳入參數。代碼如下:

@Test
    public void testOgnl3()
    {
        User user = new User();
        Map<String, Object> context = new HashMap<String, Object>();
        context.put("name", "rcx");
        context.put("password", "password");
        try
        {
            System.out.println(Ognl.getValue("getName()", context, user));
            Ognl.getValue("setName(#name)", context, user);
            System.out.println(Ognl.getValue("getName()", context, user));
            //輸出結果
            //null
            //rcx
        }
        catch (OgnlException e)
        {
            e.printStackTrace();
        }
    }

從代碼可以看出來,賦值的時候可以選擇上下文當中的元素進行給Root對象的name屬性賦值。

  5. 對數組和集合的訪問

  OGNL支持對數組按照數組下標的順序進行訪問。此方式也適用於對集合的訪問,對於Map支持使用鍵進行訪問。代碼如下:

@Test
    public void testOgnl4()
    {
        User user = new User();
        Map<String, Object> context = new HashMap<String, Object>();
        String[] strings  = {"aa", "bb"};
        ArrayList<String> list = new ArrayList<String>();
        list.add("aa");
        list.add("bb");
        Map<String, String> map = new HashMap<String, String>();
        map.put("key1", "value1");
        map.put("key2", "value2");
        context.put("list", list);
        context.put("strings", strings);
        context.put("map", map);
        try
        {
            System.out.println(Ognl.getValue("#strings[0]", context, user));
            System.out.println(Ognl.getValue("#list[0]", context, user));
            System.out.println(Ognl.getValue("#list[0 + 1]", context, user));
            System.out.println(Ognl.getValue("#map['key1']", context, user));
            System.out.println(Ognl.getValue("#map['key' + '2']", context, user));
            //輸出如下:
            //aa
            //aa
            //bb
            //value1
            //value2
        }
        catch (OgnlException e)
        {
            e.printStackTrace();
        }
    }

 從上面代碼不僅看到了訪問數組與集合的方式同時也可以看出來OGNL表達式當中支持操作符的簡單運算。有如下所示:

  2 + 4 //整數相加(同時也支持減法、乘法、除法、取余[ % / mod]、)

  "hell" + "lo" //字符串相加

  i++ //遞增、遞減

  i == j //判斷

  var in list //是否在容器當中

  6. 投影與選擇

  OGNL支持類似數據庫當中的選擇與投影功能。

  投影:選出集合當中的相同屬性組合成一個新的集合。語法為collection.{XXX},XXX就是集合中每個元素的公共屬性。

  選擇:選擇就是選擇出集合當中符合條件的元素組合成新的集合。語法為collection.{Y XXX},其中Y是一個選擇操作符,XXX是選擇用的邏輯表達式。

    選擇操作符有3種:

      ? :選擇滿足條件的所有元素

      ^:選擇滿足條件的第一個元素

      $:選擇滿足條件的最后一個元素

   示例代碼如下:

@Test
    public void testOgnl5()
    {
        Person p1 = new Person(1, "name1");
        Person p2 = new Person(2, "name2");
        Person p3 = new Person(3, "name3");
        Person p4 = new Person(4, "name4");
        Map<String, Object> context = new HashMap<String, Object>();
        ArrayList<Person> list = new ArrayList<Person>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        context.put("list", list);
        try
        {
            ArrayList<Integer> list2 = (ArrayList<Integer>) Ognl.getValue("#list.{id}", context,
                    list);
            ArrayList<String> list3 = (ArrayList<String>) Ognl.getValue("#list.{id + '-' + name}",
                    context, list);
            ArrayList<Person> list4 = (ArrayList<Person>) Ognl.getValue("#list.{? #this.id > 2}",
                    context, list);
            ArrayList<Person> list5 = (ArrayList<Person>) Ognl.getValue("#list.{^ #this.id > 2}",
                    context, list);
            ArrayList<Person> list6 = (ArrayList<Person>) Ognl.getValue("#list.{$ #this.id > 2}",
                    context, list);
            System.out.println(list2);
            System.out.println(list3);
            System.out.println(list4);
            System.out.println(list5);
            System.out.println(list6);
            //[1, 2, 3, 4]
            //[1-name1, 2-name2, 3-name3, 4-name4]
            //[Person [id=3, name=name3], Person [id=4, name=name4]]
            //[Person [id=3, name=name3]]
            //[Person [id=4, name=name4]]
            //
        }
        catch (OgnlException e)
        {
            e.printStackTrace();
        }
    }

 7. 創建對象

  OGNL支持直接使用表達式來創建對象。主要有三種情況:

  構造List對象:使用{},中間使用','進行分割如{"aa", "bb", "cc"}

  構造Map對象:使用#{},中間使用',進行分割鍵值對,鍵值對使用':'區分,如#{"key1" : "value1", "key2" : "value2"}

  構造任意對象:直接使用已知的對象的構造方法進行構造。

  示例代碼如下:

@Test
    public void testOgnl6()
    {
        try
        {
            Map<String, String> map = (Map<String, String>)Ognl.getValue("#{'key1':'value1'}", null);
            System.out.println(map);
            List<String> list = (List<String>)Ognl.getValue("{'key1','value1'}", null);
            System.out.println(list);
            Object object = Ognl.getValue("new java.lang.Object()", null);
            System.out.println(object);
            //{key1=value1}
            //[key1, value1]
            //java.lang.Object@dda25b
        }
        catch (OgnlException e)
        {
            e.printStackTrace();
        }
    }

 補充:

表達式通常用來訪問頁面中的各種變量,進行結果輸出.

    struts2中共支持以下幾種表達式語言(默認的是OGNL):

   OGNL:可以方便地操作對象屬性的開源表達式語言;

   JSTL:(JSP Standard Tag Library):JSP2.0集成的標准表達式語言;

   Groovy:基於Java平台的動態語言,它具有時下比較流行的動態語言的一些特性;

    Velocity:一種基於Java的模板匹配引擎。

一、什么是OGNL

  名稱:全稱是Object-Graph Navigation Language

   用途:是一個用來獲取 和設置 java對象屬性的表達式語言。

   應用場合:通過使用表達式語法導航對象圖,而不是直接調用對象的獲取和設置方法可以提供許多應用。比如在XML文件 或者腳本文件中嵌入OGNL表達式語法,在JSP頁面 使用OGNL表達式語法。

操作對象:基於當前對象的上下文。

二、OGNL引用方式

    屬性名稱:如對象user的屬性username,可以使用user.username來獲取.

    方法調用:可以使用user.hashCode()返回當前對象的哈希碼.

    數組元素:對於userlist數組對象,可以使用userlist[0]來引用其中的某一個元素.

三、OGNL相對其他表達式語言具有下面幾大優勢

    1)支持對象方法調用:如xxx.doSomeSpecial()

     2)支持類靜態的方法|值調用:格式為"@[類全名(包括包路徑)]@[方法名|值名]"。如:

@java.lagn.String@format('foo%s','bar')--調用類靜態方法

@tutorial.MyConstant@APP_NAME--訪問類的靜態值

 

    3)支持賦值操作和表達式串聯 :如price=100,discount=0.8,calculatePrice(),這個表達式會返回80

    4)訪問OGNL上下文 (OGNL context)和ActionContext

    5)操作集合對象

 

四、使用OGNL表達式

1)要使用OGNL表達式,首先需要在web.xml中添加ActionContextCleanUp過濾器

<filter>

<filter-name>struts-cleanup</filter-name>

<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>

</filter>

<filter-mapping>

<filter-name>struts-cleanup</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

五、'#'運算符

用途一般有三種:

1)訪問非根對象屬性,由於Struts 2中值棧被視為根對象,所以訪問其他非根對象時,需要加#前綴 。實際上,#相當於ActionContext. getContext()。

            parameters:包含當前HTTP請求參數的Map,#parameters.id[0],等價於request.getParameter("id");

            request:包含當前HttpServletRequest的屬性的Map,#request.userName,等價於request.getAttribute("username");

            session:包含當前HttpSession的屬性的Map,#session.userName,等價於session.getAttribute("username");

           application:包含當前應用的ServletContext的屬性的Map,#application.userName,等價於application.getAttribute("username");

           attr:用於按request→session→application順序訪問某個屬性,#attr.userName,等價於按順序在request,session,application范圍內讀取userName屬性,直到找到為止。

2)用於過濾和投影(projecting)集合

如person.{?#this.age>20}

 

        ? --獲取集合中所有滿足選擇邏輯的對象(拿sql來做比例就是"select * from xxx where age>20")

       ^ --獲取集合中第一個滿足選擇邏輯的對象(拿sql來做比例就是"select top(1) from xxx where age>20")

       $ --獲取集合中最后一個滿足選擇邏輯的對象

3) 用來構造Map

如#{'foo1':'bar1', 'foo2':'bar2'}

 

六、'%'運算符

用途是在標識的屬性為字符串類型時,計算OGNL表達式的值,如:

<s:url value="test.jsp?age=#userlist['admin']">→test.jsp?#userlist['admin']---可見當字符串與OGNL表達式串起來時,只會被當作字符串對待,並不執行

<s:url value="test.jsp?age=%{#userlist['admin']}">→test.jsp?age=44---使用了該符號,就可以使得OGNL表達式被執行

 

七、'$'運算符

兩個用途:

1)用於在國際化資源文件中,引用OGNL表達式。例如在資源文件中有一個標簽fileName,則可以在資源文件中引用:

validation.require=${getText(fileName)} is required

 

2)在struts2配置文件中引用OGNL表達式,如:

<action name="AddPhoto" class="addPhoto">

<result type="redirect">ListPhotos.action?albumId=${albumId}</result>--但這個albumId是從哪來的呢?

</action>

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM