OGNL介绍:
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。这样可以更好的取得数据。
OGNL可以让我们用非常简单的表达式访问对象层,例如,当前环境的根对象为user1,则表达式person.address[0].province可以访问到user1的person属性的第一个address的province属性。
这种功能是模板语言的一个重要补充,像jsp2.0,velocity,jelly等等,都有类似的功能,但是ognl比它们完善得多,而且以一个独立的lib出现,方便我们构建自己的框架。
表达式:
OGNL支持各种纷繁复杂的表达式。但是最最基本的表达式的原型,是将对象的引用值用点串联起来,从左到右,每一次表达式计算返回的结果成为当前对象,后面部分接着在当前对象上进行计算,一直到全部表达式计算完成,返回最后得到的对象。OGNL则针对这条基本原则进行不断的扩充,从而使之支持对象树、数组、容器的访问,甚至是类似SQL中的投影选择等操作。
1. 基本对象树的访问
对象树的访问就是通过使用点号将对象的引用串联起来进行。
例如:xxxx,xxxx.xxxx,xxxx. xxxx. xxxx. xxxx. xxxx
2. 对容器变量的访问
对容器变量的访问,通过#符号加上表达式进行。
例如:#xxxx,#xxxx. xxxx,#xxxx.xxxxx. xxxx. xxxx. xxxx
3. 使用操作符号
OGNL表达式中能使用的操作符基本跟Java里的操作符一样,除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外,还能使用 mod, in, not in等。
4. 容器、数组、对象
OGNL支持对数组和ArrayList等容器的顺序访问:例如:group.users[0]
同时,OGNL支持对Map的按键值查找:
例如:#session['mySessionPropKey']
不仅如此,OGNL还支持容器的构造的表达式:
例如:{"green", "red", "blue"}构造一个List,#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}构造一个Map
你也可以通过任意类对象的构造函数进行对象新建:
例如:new Java.net.URL("xxxxxx/")
5. 对静态方法或变量的访问
要引用类的静态方法和字段,他们的表达方式是一样的@class@member或者@class@method(args):
例如:@com.javaeye.core.Resource@ENABLE,@com.javaeye.core.Resource@getAllResources
6. 方法调用
直接通过类似Java的方法调用方式进行,你甚至可以传递参数:
例如:user.getName(),group.users.size(),group.containsUser(#requestUser)
7. 投影和选择
OGNL支持类似数据库中的投影(projection) 和选择(selection)。
投影就是选出集合中每个元素的相同属性组成新的集合,类似于关系数据库的字段操作。投影操作语法为 collection.{XXX},其中XXX 是这个集合中每个元素的公共属性。
例如:group.userList.{username}将获得某个group中的所有user的name的列表。
选择就是过滤满足selection 条件的集合元素,类似于关系数据库的纪录操作。选择操作的语法为:collection.{X YYY},其中X 是一个选择操作符,后面则是选择用的逻辑表达式。而选择操作符有三种:
? 选择满足条件的所有元素
^ 选择满足条件的第一个元素
$ 选择满足条件的最后一个元素
例如:group.userList.{? #txxx.xxx != null}将获得某个group中user的name不为空的user的列表。
Ognl其实就是Map,它又分为一个根对象(Root)和多个非根对象
非根对象要通过"#key"访问,根对象可以省略"#key"
比如我们获取一个为根对象的的对象的属性,就只需要直接根据属性名就好了:String employeeName = (String) OnglExpression.getValue(“name”, ctx, e);
如果不是根对象: String managerName (String)OnglExpression.getValue("#manager.name",ctx, e);
对象取值和非根对象取值的现象,以及OGNL取值和赋值的案例
6 public class Demo1 { 7 8 /** 9 * @param args 10 * @throws OgnlException 11 */ 12 public static void main(String[] args) { 13 Employee e = new Employee(); 14 e.setName("小李"); 15 16 Manager m = new Manager(); 17 m.setName("张经理"); 18 19 // 创建OGNL下文,而OGNL上下文实际上就是一个Map对象 20 OgnlContext ctx = new OgnlContext(); 21 22 // 将员工和经理放到OGNL上下文当中去 23 ctx.put("employee", e); 24 ctx.put("manager", m); 25 ctx.setRoot(e);// 设置OGNL上下文的根对象 26 27 /** ********************** 取值操作 *************************** */ 28 // 表达式name将执行e.getName(),因为e对象是根对象(请注意根对象和非根对象表达式的区别) 29 String employeeName = (String) OnglExpression.getValue("name", ctx, e); 30 System.out.println(employeeName); 31 32 // 表达式#manager.name将执行m.getName(),注意:如果访问的不是根对象那么必须在前面加上一个名称空间,例如:#manager.name 33 String managerName = (String) OnglExpression.getValue("#manager.name", 34 ctx, e); 35 System.out.println(managerName); 36 37 // 当然根对象也可以使用#employee.name表达式进行访问 38 employeeName = (String) OnglExpression.getValue("#employee.name", ctx, 39 e); 40 System.out.println(employeeName); 41 42 /** ********************** 赋值操作 *************************** */ 43 OnglExpression.setValue("name", ctx, e, "小明"); 44 employeeName = (String) OnglExpression.getValue("name", ctx, e); 45 System.out.println(employeeName); 46 47 OnglExpression.setValue("#manager.name", ctx, e, "孙经理"); 48 managerName = (String) OnglExpression.getValue("#manager.name", ctx, e); 49 System.out.println(managerName); 50 51 OnglExpression.setValue("#employee.name", ctx, e, "小芳"); 52 employeeName = (String) OnglExpression.getValue("name", ctx, e); 53 System.out.println(employeeName); 54 } 55 56 }
OGNL向ValueStack压栈
后台定义属性和实现modelDriver接口,提供get和set方法
1 private HttpServletRequest req; 2 private Cal cal1=new Cal(); 3 private Cal cal2; 4 private String sex; 5 private String num1; 6 7 8 public String getNum1() { 9 return num1; 10 } 11 12 13 public void setNum1(String num1) { 14 this.num1 = num1; 15 } 16 17 18 public Cal getCal2() { 19 return cal2; 20 } 21 22 23 public void setCal2(Cal cal2) { 24 this.cal2 = cal2; 25 } 26 27 28 public String getSex() { 29 return sex; 30 } 31 32 33 public void setSex(String sex) { 34 this.sex = sex; 35 } 36 37 /** 38 * implements ModelDriven 39 * @return 40 */ 41 public String accept1() { 42 System.out.println("cal1:"+cal1); 43 System.out.println("num1:"+num1); 44 return "rs"; 45 }
运行显示cal1.num1有值,而num1却取不到值
这就和ValueStack的压栈有关系了,压栈的结构是先进后出,而ValueStack的取值是取到了值就会返回,不会往下取了。
而ValueStack对取值的压栈是先把xxxAction也就是我们通过set和get方法取值的方式先压入栈底,然后再把ModelDriver压入,所有会先取到通过ModelDriver来获取值的,而获取到了就返回了,导致后面的值不会获取了。