1.简介
OGNL:Object Graph Navigation Language,是一种功能强大的表达式语言,可以存取对象的属性,调用对象的方法等。
著名的Struts2使用它来实现UI和Action之间的数据绑定。
2.两个重要的API
Ognl.getValue(String expression, Object root);
从root对象中获取expression对应的值
Ognl.getValue(String expression, Map<String, Object> context, Object root);
从根对象为root的上下文context中获取expression对应的值
我们可以从下面一段代码中看出context和root的区别
User user = new User(); user.setId("001"); Map<String, String> ognlCtxt = new HashMap<String, String>(); ognlCtxt.put("id", "007"); assertEquals("001", Ognl.getValue("id", ognlCtxt, user)); assertEquals("001", Ognl.getValue("#root.id", ognlCtxt, user)); assertEquals("007", Ognl.getValue("#id", ognlCtxt, user)); assertEquals("007", Ognl.getValue("#context.id", ognlCtxt, user));
当expression以#开头时,将从context中取值
当expression直接以property名字开头时,将从root中取值
并且context中有两个属性#root指向root对象,#context指向本身
具体原因请参考OGNL源代码
3.主要使用
1)常量
--String:用'或"包围
--char:用'包围
--数字:数字格式,或者添加后缀b(B,表示BigDecimals),后缀h(H,表示BigIntegers)
--Boolean:保留字true/false
--null:保留字null
// String assertEquals("id", Ognl.getValue("\"id\"", null)); assertEquals("id", Ognl.getValue("'id'", null)); // char assertEquals('i', Ognl.getValue("'i'", null)); // Number assertEquals(22, Ognl.getValue("22", null)); // boolean assertTrue((Boolean) Ognl.getValue("true", null)); // null assertNull(Ognl.getValue("null", null));
2)new新建对象
--java.lang包中的类对象:new
new String()
--其它包中的类对象:new,但要使用类全名
new java.util.ArrayList()
--List:用大括号包围,元素之间用","分隔
{"badminton", "CS"}
--数组:和Java类似
new int[]{1, 2, 3}
new int[5]
--Map:以#开头,用大括号包围,类似于Json格式,Key和Value之间用":"分隔,Entry之间使用"," 分隔
可以同构在#之后用"@"包围的类全名来指定
#{"name" : "007", "age" : 45}
#@java.util.LinkedHashMap@{"name" : "007", "age" : 45}
// object in java.lang.* assertTrue(Ognl.getValue("new String()", null) instanceof String); // object not in java.lang.* assertTrue(Ognl.getValue("new java.util.ArrayList()", null) instanceof List); /* Collection */ // List assertTrue(Ognl.getValue("{0, 1, 2}", null) instanceof List); // Array assertTrue(Ognl.getValue("new int[]{0, 1, 2}", null) instanceof int[]); assertTrue(Ognl.getValue("new int[5]", null) instanceof int[]); // Map assertTrue(Ognl.getValue("#{'name' : 'man', 'age' : 25}", null) instanceof Map); assertTrue(Ognl.getValue("#@java.util.HashMap@{'name' : 'man', 'age' : 25}", null) instanceof HashMap);
3)获取对象属性
通过.或者[]访问,以下内容均可视为对象的属性
--JaveBean中的属性
--List或者Array对象的index
--Map对象的key
--[]还支持对一下成对出现方法的index的直接访问(必须成对出现)
public PropertyType getPropertyName(int index);
public void setPropertyName(int index, PropertyType value);
public PropertyType getPropertyName(IndexType index);
public void setPropertyName(IndexType index, PropertyType value);
--除此之外为了OGNL还为Collection对象提供了一些伪属性
Collection : size/isEmpty
List : iterator
Map : keys, values(注:假如Map中有一key的名字为size,则必须通过[]方式获取,.方式将返回Map的大小值)
Set : iterator
Iterator : next/hasNext
Enumeration : next/hasNext/nextElement/hasMoreElements
--.和[]的区别:[]支持表达式
User user = new User(); user.setId("001"); user.setName("man1"); user.setAge(22); List<String> hobbies = new ArrayList<String>(); hobbies.add("badminton"); hobbies.add("name"); user.setHobbies(hobbies); Map<String, List<String>> relations = new HashMap<String, List<String>>(); List<String> friends = new ArrayList<String>(); friends.add("002"); relations.put("friends", friends); user.setRelations(relations); //property assertEquals("001", Ognl.getValue("id", user)); /*index*/ // List assertEquals("badminton", Ognl.getValue("hobbies[0]", user)); // Map assertEquals("002", Ognl.getValue("relations['friends'][0]", user)); // getHobby(...)/setHobby(...) assertEquals("badminton", Ognl.getValue("hobby[0]", user)); // getRelation(...)/setRelation(...) assertEquals("002", Ognl.getValue("relation['friends'][0]", user)); //difference between . and [] assertEquals("man1", Ognl.getValue("[hobbies[1]]", user)); // pseudo property assertEquals(2, Ognl.getValue("hobbies.size", user));
4)调用方法
直接通过.method(param1, ..., paramN)的方式访问
注意:当方法重载,并且参数符合多个方法要求时,OGNL会选择任意一个进行执行。
所以当方法存在重载,并且参数中有null值时需特别注意,因为null符合任何参数类型要求
assertEquals(2, Ognl.getValue("{0, 1}.size()", null));
5)Static属性和方法
--static属性@class@field
--static方法@class@method(param1, ..., paramN)
// static method assertEquals("User", Ognl.getValue("@com.siyuan.ognltest.entity.User@getEntityName()", null)); // static field assertEquals("User", Ognl.getValue("@com.siyuan.ognltest.entity.User@ENTITY_NAME", null));
6)变量
以#开头的属性名均作为context中的变量,并且可通过=对其进行赋值,假如不存在,则新建并保存在context中
#this为一特殊变量,指示前一段表达式的值
assertEquals(120, Ognl.getValue("#count = 100, #count + 20", null)); assertEquals(120, Ognl.getValue("(#count=100).(#this>100 ? 2*#this : 20+#this)", null)); OgnlContext ognlCtxt = new OgnlContext(); assertEquals(120, Ognl.getValue("#count = 100, #count + 20", ognlCtxt, "")); assertEquals(100, Ognl.getValue("count", ognlCtxt));
7)运算符
除了Java中的运算符,OGNL添加了下列特殊的运算符
--in/not in
返回boolean值,表示元素是否存在list或array中
--projection
collection.{ognlExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后的值
--match
collection.{? ognlBooleanExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后为true的元素
--first match
collection.{^ ognlBooleanExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后第一个为true的元素
--last match
collection.{$ ognlBooleanExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后最后一个为true的元素
// in & not in assertTrue((Boolean) Ognl.getValue("'badminton' in {'badminton', 'CS'}", null)); assertTrue((Boolean) Ognl.getValue("4 not in new int[]{1, 2, 3}", null)); User user = new User(); user.setId("000"); User user1 = new User(); user1.setId("001"); User user2 = new User(); user2.setId("002"); List<User> users = new ArrayList<User>(); users.add(user); users.add(user1); users.add(user2); // projection List<String> ids = (List<String>) Ognl.getValue("#root.{id}", users); assertEquals("000", ids.get(0)); assertEquals("001", ids.get(1)); assertEquals("002", ids.get(2)); // selection List<User> filteredUsers = (List<User>) Ognl.getValue("#root.{? #this.id instanceof String}", users); assertEquals(user, Ognl.getValue("#root[0]", filteredUsers)); // first match List<User> filteredUsers1 = (List<User>) Ognl.getValue("#root.{^ #this.id instanceof String}", users); assertEquals(user, Ognl.getValue("#root[0]", filteredUsers1)); List<User> filteredUsers2 = (List<User>) Ognl.getValue("#root.{$ #this.id instanceof String}", users); assertEquals(user2, Ognl.getValue("#root[0]", filteredUsers2));
4.参考资料