1. OGNL 简介
OGNL是Object Graph Navigation Language(对象图形导航语言)的缩写。要学习好struts2标签的取值,首先得先弄清楚ognl表达式的取值原理。OGNL的取值原理其实就是从一个大的ognl上下文(OgnlContext)中,通过相应的表达式语句,对一个对象的属性进行获取或者对方法进行调用。上下文中还包含一个唯一的root对象,root可以通过程序进行指定。
2. OGNL 的简单使用
首先准备示例的类Person和Department,一个Person属于一个Department
public class Person {
private String name;
private int age;
private Department department;
// getter和setter方法
// ...
}
public class Department {
private String name;
// getter和setter方法
// ...
}
2.1 设置root和上下文
// 1. 通过setRoot方法进行指定
Ognl.setRoot(Map context, Object root);
// 2. 获取值的时候,通过getValue的重载传入
Ognl.getValue(...)
下面设置root和上下文的时候采用第二种方式。。。其实通过setRoot方法可以看出,OGNL上下文其实就是一个大的Map,然后其中包含一个key为”root”的对象。
2.2 操作简单属性
Person p = new Person();
p.setName("mimosa");
p.setAge(22);
// 获取简单属性name或者age
System.out.println(Ognl.getValue("name", p));
// 或者通过类似js属性获取的方式
System.out.println(Ognl.getValue("['name']", p));
// 输出:
// mimosa
此时的root对象是Person对象p,要是没有指定上下文默认就是一个包含root(p)的上下文Map,然后通过表达式”name”对p中name属性的值进行获取。这里的OGNL结构:
下面还有一个就是从root中取值和从ognlContext取值的表达式又是不相同的。
如果表达式中没有以”#”号开通,那么就从根(root)中取值。
如果包含”#”,那么就从上下文中取值。
所以上面获取name的方式还可以改为如下:
System.out.println(Ognl.getValue("#root.name", p));
2.3 操作引用属性
Department d = new Department();
d.setName("火星");
Person p = new Person();
p.setName("mimosa");
p.setAge(22);
p.setDepartment(d);
// 获取引用的属性值
System.out.println(Ognl.getValue("department.name", p))
// 输出:
// 火星
这里稍微想想就能理解,不多说了。
2.4 设置上下文
Person p1 = new Person();
p1.setName("张三");
p1.setAge(20);
Person p2 = new Person();
p2.setName("李四");
p2.setAge(30);
// 上下文其实就是一个Map
Map context = new HashMap();
context.put("p1", p1);
context.put("p2", p2);
System.out.println(Ognl.getValue("name", context, p1));
System.out.println(Ognl.getValue("#p1.name", context, p1)
System.out.println(Ognl.getValue("#p2.name", context, p1)
// 输出:
// 张三
// 张三
// 李四
刚刚说了,上下文其实就是一个Map,这里getValue第二个参数就是设置上下文,第三个参数是设置根(root)。其实根可以随便指定的,root指向上下文都没有关系,只是要理清楚上下文的结构,那么取值就可以变得十分简单。
通过这里的ognl上下文结构就可以一目了然:
然后分析表达式:
1. “name” – 没有”#”号,默认从根(p1)中取值。
2. “#p1.name” – 从上下文中取,Map中key为”p1”的值为Person对象p1。
3. “#p2.name” – 同上。
2.5 调用方法
Person p = new Person();
System.out.println(Ognl.getValue("sayHello('you')", p));
// 输出:
// hello you
ognl比较强大的地方就是支持方法的调用。
2.6 操作集合或数组
操作集合和数组当然需要借助索引进行获取。
Person p1 = new Person();
p1.setName("张三");
p1.setAge(20);
Person p2 = new Person();
p2.setName("李四");
p2.setAge(30);
List list = new ArrayList();
list.add(p1);
list.add(p2);
System.out.println(Ognl.getValue("[0].name", list));
// 或者
System.out.println(Ognl.getValue("#root[0].name", list)
// 输出:
// 张三
// 张三
数组与之类似。但是想到上面可以进行方法的调用,那么List的get方法是否还会起作用?答案是肯定的。
// 这样依然可以获取
System.out.println(Ognl.getValue("get(0).name", list));
2.7 调用静态方法或属性
使用两个”@”符号对静态方法进行调用,第一个@后面跟类的前面,第二个@后面跟静态方法或者静态属性。
这里特别注意的是如果是java.lang.Math类,那么第一个@后面可以不跟东西。
System.out.println(Ognl.getValue("@java.lang.Math@max(1,2)", null)); // 2
System.out.println(Ognl.getValue("@@max(1,2)", null)); // 2
System.out.println(Ognl.getValue("@@PI", null)); // 3.141592653589793
2.8 映射集合或者Map
通过表达式 “{1,’ss’,20}” 可以映射出一个ArrayList集合。
System.out.println(Ognl.getValue("{1,'ss',20}[1]", null)); // ss
通过表达式 “#{‘key1’:2,’key2’:’ss’}” 可以映射出一个 LinkedHashMap,注意 “#” 开头。
System.out.println(Ognl.getValue("#{'key1':2,'key2':'ss'}.key1", null)); // 2
System.out.println(Ognl.getValue("#{'key1':2,'key2':'ss'}['key2']", null)); // ss
3. 其他表达式
3.1 过滤表达式
过滤是针对集合进行处理的,表达式为:coloection.{?expression}
Person p1 = new Person();
p1.setName("张三");
p1.setAge(20);
Person p2 = new Person();
p2.setName("李四");
p2.setAge(30);
List list = new ArrayList();
list.add(p1);
list.add(p2);
System.out.println(Ognl.getValue("#root.{?#this.age>=30}", list));
// 过滤出年龄大于等于30的对象
这里的代码筛选出了p2,返回类型是一个集合。”#this”表示当前处理的对象。
也可以通过表达式 coloection.{^expression} 来对集合第一个元素进行处理,通过coloection.{$expression} 来对集合最后一个元素进行处理。
3.2 投影
也可以通过这种表达式 coloection.{expression} 进行更加复杂的操作。
// 投影出name属性, 返回一个集合
System.out.println(Ognl.getValue("#root.{name}", list)); // [张三, 李四]
// 对投影的值进行筛选, 注意{}开头没有"?"号
System.out.println(Ognl.getValue("#root.{#this.age>=30?'gt30':#this.age}", list)); // [20, gt30]
4. 总结
综上ognl表达式确实比较强大,但是也简单易懂。在struts2标签中获取想要的值的时候,无非也就是从大的ognl上下文中去获取,所以在学习标签之前要对ognl表达式有一定的了解。最后附上struts2中ognl大致的结构图: