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(); } }
這篇OGNL的介紹就到這里,本文並沒有把OGNL的所有內容都介紹出來,主要介紹了OGNL的一些簡單的知識,后面有時間的話我會陸續介紹OGNL的相關知識,並且結合Struts2深入分析下OGNL的構成。同樣謝謝大家的閱讀,本人寫博文的時候難免有錯誤的地方,如果大家發現希望大家給予指正,謝謝。