主要内容
OGNL简介
OGNL是一种表达式语言,用于简化从特定对象中获取数据的方式。要使用ognl提供的功能,项目中必须导入两个包,分别是ognl-xxx.jar和javassist-xxx.jar。
OGNL的主要组成部分:
- 根对象
- 上下文对象
什么是根对象
首先OGNL操作的是数据,也就是获取和设置数据的值。那么数据从哪里来?这个就是根对象。根对象只能有一个,但是根对象里面的数据可以很复杂。简单来说,根对象可以是一个javabean。例如一个Person
对象,Person对象除了保存简单的字段如String name
和int age
,还可以保存复杂的对象如Pat
,例如这个人养了一只宠物。
使用OGNL表达式操作对象
一般来说,我们是这样操作这个对象的:
1 2 |
//获取这个人养的宠物名称 String patName = person.getPat().getName(); |
要和上面的代码获得同样的效果,使用ognl的方式,只需要改动一行代码:
1 |
Object patName = Ognl.getValue("pat.name", person); |
我们来看看getValue()
方法的签名:
1 |
public static Object getValue( String expression, Object root ) throws OgnlException |
其中expression参数就是ognl的表达式,而第二个参数就是我们获取数据的对象,也就是数据源。expression表达式就是从第二个参数中获取数据的。这个参数就是OGNL中的根对象。
详细一点的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Person person = new Person(); person.setName("Jack"); Pat pat = new Pat(); pat.setName("hello kitty"); person.setPat(pat); try { //获取这个人的名称 Object name = Ognl.getValue("name", person); //获取这个人养的宠物的名称 Object patName = Ognl.getValue("pat.name", person); System.out.println(name); System.out.println(patName); } catch (OgnlException e) { e.printStackTrace(); } |
OGNL的基本语法
像上面的代码中,我们通过pat.name的方式来获取宠物的名称,这种写法在OGNL中称为导航链,导航链是OGNL的基本单位,通常简称为链。最简单的链包括下面几个部分:
- 属性名称
- 方法调用
- 数组元素
也就是说,OGNL除了能够获取对象的属性外,还能调用它们的方法,例如:
1 2 |
Object name = Ognl.getValue("name.toUpperCase()", person); Object patName = Ognl.getValue("pat.name.toUpperCase()", person); |
甚至获取的数据是数组类型,OGNL处理起来也是轻松自如:
1 |
Object carName = Ognl.getValue("cars[1].name", person); |
什么是上下文对象
OGNL的根对象只能有一个,根对象中保存的数据往往都是相关的。如果我们有更多的数据需要处理,而且这些数据看起来并没有多大的联系,那么就可以使用上下文对象。上下文对象是Map类型的对象,因此上下文中的数据理所当然就是以键值的方式保存的。
Ognl除了提供两个参数的getValue()
方法外,还有三个参数的getValue()
方法,如下:
1 |
public static Object getValue( String expression, Map context, Object root ) throws OgnlException |
其中第二个参数就是我们要说的上下文对象。
创建和使用上下文对象
既然上下文对象只是一个Map类型的对象,那么只需要和平时一样创建Map对象即可:
1 2 3 4 5 |
//创建一个上下文对象 Map<String, String> ctx = new HashMap<>(); //在对象中存放数据 ctx.put("dog", "snoopy"); |
使用OGNL的getValue()
方法获取上下文中的数据,我们分别使用两个参数和三个参数的getValue()
方法。
1 2 3 4 5 |
//使用两个参数的getValue方法, ctx作为根对象 Objet dogName = Ognl.getValue("dog", ctx); //使用三个参数的getValue方法 person中没有dog属性,直接抛出异常 Object dogName = Ognl.getValue("dog", ctx, person); |
两个参数和三个参数的方法有什么区别呢?如果同时使用上下文对象和根对象,get方法会优先从根对象获取数据,如果根对象找不到对应的属性,就抛出OgnlException,不会继续到上下文中寻找
使用#号操作根对象和上下文对象
作为OGNL的两个主要数据源,可以直接在表达式中使用#号来访问这两个对象,例如:
1 2 |
Object ctxAddress = Ognl.getValue("#context", ctx, person); Object rootAddress = Ognl.getValue("#root", person); |
输出结果:
1 2 |
ognl.OgnlContext@ca7e09f8 cn.sharpcode.ognldemo.Person@37f8bb67 |
然后,我们就可以指定表达式的数据源:
1 2 3 4 5 |
//获取上下文中的数据 Object dogName = Ognl.getValue("#context.dog", ctx, person); //获取根对象中的数据 Object patName = Ognl.getValue("#root.pat.name", person); |
OGNL高级应用
过滤和投影。这两个概念主要是用来操作数组或者是集合的,过滤和投影可以把数组或集合中不符合条件的数据过滤掉然后返回一个全新的包含指定数据的集合。
基本语法:dataSource.{property}
例如, 我要获取person中拥有的车辆的名称,可以简单使用下面的方式:
1 2 3 4 |
Object allCarName = Ognl.getValue("cars.{name}", person); //输出 [BMW, BMW, HONDA] System.out.println(allCarName); |
上面的cars.{name}
语法就是用来获取数组或集合的,括号中的name就是要获取的字段,该字段是使用点"."
前面的对象作为上下文的,这里是cars
对象,而cars对象也是person根对象的字段属性。
过滤不符合条件的数据
使用OGNL表达式,我们可以很轻松地把不符合要求的数据过滤掉,然后返回一个全新的集合。
下面的代码获取所有名称为BMW的车辆
1 2 |
//获取名称为BMW的车辆 Object allCarName = Ognl.getValue("cars.{? #this.name == 'BMW'}", person); |
#this
是对cars
的一个引用。#this.name
可用来获取所有cars对象的名称并把它们封装到一个新集合中。因此,cars.{#this.name}
实际相当于上面的cars.{name}
。也就是说,可以这样获取名称为BMW的所有车辆
1 2 |
//获取名称为BMW的车辆 Object allCarName = Ognl.getValue("cars.{? name == 'BMW'}", person); |
- 获取名称不是BMW的车辆的名称,采用了链式写法
1 2 3 4 5 6 7 8 9 |
//名称不为BMW的车辆对象集合 Object notBMW = Ognl.getValue("cars.{? name != 'BMW'}", person); //输出 [cn.sharpcode.ognldemo.Car@306a30c7, cn.sharpcode.ognldemo.Car@b81eda8] System.out.println(notBMW); //名称不为BMW的车辆名称集合 ,使用了OGNL表达式的链式写法 Object notBMW2 = Ognl.getValue("cars.{? name != 'BMW'}.{name}", person); //输出 [Benz, HONDA] System.out.println(notBMW2); |
- 获取数据中第一辆名称不为BMW的车辆,使用 “^”符号
1 2 |
//获取第一辆名称不是BMW的车辆 Object Benz = Ognl.getValue("cars.{^ name != 'BMW'}[0].name", person); |
- 获取数据中最后一辆名称不是BMW的车辆,使用”$”符号
1 2 |
//获取最后一辆名称不是BMW的车辆 Object honda = Ognl.getValue("cars.{$ name != 'BMW'}[0].name", person); |
使用OGNL调用静态方法
基本语法 @package_name@method_name
1 2 3 4 5 6 |
//salary = 3333.53 //向下取整 3333.0 Object floorSalary = Ognl.getValue("@java.lang.Math@floor(salary)", person); //向上取整 3334.0 Object ceilSalary = Ognl.getValue("@java.lang.Math@ceil(salary)", person); |
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
package cn.sharpcode.ognldemo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import ognl.Ognl; import ognl.OgnlException; public class Entry { public static void main(String[] args){ Person person = new Person(); person.setName("Jack"); person.setSalary(3333.53f); Pat pat = new Pat(); pat.setName("hello kitty"); List<Car> cars = new ArrayList<>(); cars.add(new Car("BMW")); cars.add(new Car("BMW")); cars.add(new Car("Benz")); cars.add(new Car("HONDA")); person.setPat(pat); person.setCars(cars); Map<String, String> ctx = new HashMap<>(); ctx.put("dog", "snoopy"); try { //把name转换为大写 Object name = Ognl.getValue("name.toUpperCase()", person); //获取person中cars字段的长度 Object howManyCars = Ognl.getValue("cars.size()", person); //获取person中第一台车辆的名称 Object carName = Ognl.getValue("cars[0].name", person); //获取上下文中键为dog的值 Object dogName = Ognl.getValue("#context.dog", ctx, person); //获取person的宠物名称 Object patName = Ognl.getValue("#root.pat.name", person); //获取名称不是BMW的车辆对象集合 Object notBMW = Ognl.getValue("cars.{? name != 'BMW'}", person); //获取名称不是BMW的车辆名称集合 Object notBMW2 = Ognl.getValue("cars.{? name != 'BMW'}.{name}", person); //获取第一辆名称不是BMW的车辆 Object Benz = Ognl.getValue("cars.{^ name != 'BMW'}[0].name", person); //获取最后一辆名称不是BMW的车辆 Object honda = Ognl.getValue("cars.{$ name != 'BMW'}[0].name", person); Object floorSalary = Ognl.getValue("@java.lang.Math@floor(salary)", person); Object ceilSalary = Ognl.getValue("@java.lang.Math@ceil(salary)", person); System.out.println(name); System.out.println(howManyCars); System.out.println(carName); System.out.println(dogName); System.out.println(patName); System.out.println(notBMW); System.out.println(notBMW2); System.out.println(Benz); System.out.println(floorSalary); System.out.println(ceilSalary); } catch (OgnlException e) { e.printStackTrace(); } } } class Person{ private String name; private Pat pat; private List<Car> cars; private float salary; public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } public List<Car> getCars() { return cars; } public void setCars(List<Car> cars) { this.cars = cars; } public Pat getPat() { return pat; } public void setPat(Pat pat) { this.pat = pat; } public String getName() { return name; } public void setName(String name) { this.name = name; } private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } class Car{ private String name; public Car(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Pat{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return this.name; } } |
转载请注明:Pure nonsense » OGNL详解