OGNL类库

OGNL概述

定义

  • OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个开源项目。Struts框架使用OGNL作为默认的表达式语言。

特性

  • Ognl有三个核心类,Ognl,OgnlContext,OgnlRuntime
    • Ognl:Ognl的核心操作类,封装多种函数。解析表达式,生成上下文,以及提取表达式中的内容等
    • OgnlContext:是Ognl的上下文环境,本质是一个Map,存储需要被表达式解析提取的数据。
    • OgnlRuntime:可理解为Ognl的配置类,提供多种配置和接口,实现Ognl的自定义特性
  • 此外OgnlContext能设置根(Root)元素,当设置根元素时,取值不需要添加#,mybatis框架中#{}表达式中的Ognl表达式正是用到了根元素

案例

Ognl表达式取值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void testOGNL() throws OgnlException {
//定义测试类,这是个实体类,里面有id,name属性
Student student = new Student();
student.setName("ypjiao");
student.setId(1);
//初始ognl上下文
OgnlContext ognlContext = new OgnlContext();
//存入实体
ognlContext.put("student",student);
//该方法的第一个参数为表达式,第二个参数为上下文,第三个参数可从上下文中获取root元素,此例中root未设置,为空
Object value = Ognl.getValue("#student.name", ognlContext, ognlContext.getRoot());
out.println(value);
Object expression = Ognl.parseExpression("#student.id");
Object value1 = Ognl.getValue(expression, ognlContext, ognlContext.getRoot());
out.println(value1);
}

Ognl表达式获取Root元素

  • root元素中不需要传#
1
2
3
4
5
6
7
8
Student student = new Student();
student.setName("ypjiao");
OgnlContext ognlContext = new OgnlContext();
//设置根元素(根元素不同于ognlContext中的Map集合
ognlContext.setRoot(student);
//取根元素不需要#,且表达式中无需包含根元素
Object value = Ognl.getValue("name", ognlContext, ognlContext.getRoot());
out.println(value);

Ognl表达式创建数组和对象

1
2
3
4
5
6
7
OgnlContext ognlContext = new OgnlContext();
Object expression = Ognl.parseExpression("{'aaa','bbb','ccc'}");
//返回的object对象为一个数组
Object value = Ognl.getValue(expression, ognlContext, ognlContext.getRoot());
out.println("array="+value);


Ognl调用静态方法

1
2
3
4
OgnlContext ognlContext = new OgnlContext();
Object expression = Ognl.parseExpression("@Math@random()");
Object value = Ognl.getValue(expression, ognlContext, ognlContext.getRoot());
out.println("random="+value.toString());

Ognl调用方法

1
2
3
4
5
6
7
Student student = new Student();
student.setName("Andrew");
OgnlContext ognlContext = new OgnlContext();
ognlContext.put("student_Andrew",student);
Object expression = Ognl.parseExpression("#student_Andrew.getName()");
Object value = Ognl.getValue(expression, ognlContext, ognlContext.getRoot());
out.println("name="+value.toString());

其它特性

Property访问器

我们可以注册自定义解析器以及解析对象,用于解析特殊的数据或达到解析自定义。当注册完成后,Ognl在解析数据时当发现有注册过的对象类型,则会调用专门的解析器的get方法来读取数据;

我们需要分别实现解析器解析对象

解析器

  • 解析器需要实现PropertyAccessor接口
  • 实现接口中的方法来达到自定义
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
//本例中会从ypMap集合中获取一个key为test_ypjiao的对象
class YpAccessor implements PropertyAccessor{
@Override
//参数1是OgnlContext对象,参数2是解析对象,参数3是分割后的ognl表达式(ognl表达式会被.分割)
public Object getProperty(Map map, Object target, Object o1) throws OgnlException {
Map ypMap = (Map)target;
Object parameterObject = ypMap.get("test_ypjiao");
if (parameterObject instanceof Map) {
return ((Map)parameterObject).get(o1);
}
return parameterObject;
}

@Override
public void setProperty(Map map, Object target, Object o1, Object o2) throws OgnlException {
Map<String,Object> ypMap = (Map<String,Object>)target;
ypMap.put((String)o1,o2);
}

@Override
public String getSourceAccessor(OgnlContext ognlContext, Object o, Object o1) {
return null;
}

@Override
public String getSourceSetter(OgnlContext ognlContext, Object o, Object o1) {
return null;
}
}

解析对象

解析类型一般是一个集合,完全自定义,他们最终会作为参数传递给解析器的get或set方法以便调用;

我们可以通过第二个参数获取到解析类型对象,本例中解析对象是一个继承自HashMap的集合

1
2
class YpMap extends HashMap {
}

案例调用

  • 需要新的解析对象时,都应该注册
  • 本例中会将实体对象Student存入自定义集合YpMap中,且key为一个写死的固定值,不会从表达式中获取和传输这个固定值,目的是为了让自定义的解析器通过写死的key获取到我们需要的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void testOGNLArray() throws OgnlException {
OgnlRuntime.setPropertyAccessor(YpMap.class,new YpAccessor());

YpMap ypMap = new YpMap();
Student student = new Student();
student.setName("ypjiao");
student.setId(1);
//写死key
ypMap.put("test_ypjiao", student);
//我们还可以通过Ognl来创建上下文context,且还能设置个性化配置,本利我们设置Property访问器
//该方法的第一个参数是我们的集合,它会把他设为root
Map ognlContext = Ognl.createDefaultContext(ypMap, new DefaultClassResolver(), new DefaultTypeConverter(), new DefaultMemberAccess(true));
//理论上从student.name是无法解析出来的,因为student对象是存储在ypMap(root)集合中的,它需要通过专有的key来获取出student;但本例中我们实现了类型解析器,因此能取出来student随后进行后续的逐步解析
Object value = Ognl.getValue("student.name", ognlContext, ypMap);
out.println("name="+value);
}

OGNL类库
https://andrewjiao.github.io/2021/01/01/Ognl类库/
作者
Andrew_Jiao
发布于
2021年1月1日
许可协议