OGNL 基础使用和入门

一、什么是OGNL

OGNL是Object Graph Navigation Language的缩写,中文意思是对象导航图语言。它是一种开源的表达式语言(Expression Language),被集成在Struts2等框架中,主要用于对数据进行访问。它拥有类型转换、访问对象方法、操作集合对象等功能,并可以通过简单的语法存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。

OGNL支持各种纷繁复杂的表达式。但是最最基本的表达式的原型,是将对象的引用值用点串联起来,从左到右,每一次表达式计算返回的结果成为当前对象,后面部分接着在当前对象上进行计算,一直到全部表达式计算完成,返回最后得到的对象。OGNL则针对这条基本原则进行不断的扩充,从而使之支持对象树、数组、容器的访问,甚至是类似SQL中的投影选择等操作。

 

OGML三要素包括:

  1. 根对象(Root Object):OGML表达式的起始点,表示要导航和操作的对象图的根节点。
  2. 上下文(Context):包含了表达式求值过程中使用的变量和对象,可以在表达式中引用。上下文可以是一个Map对象,其中存储了变量名和对应的值。
  3. 表达式(Expression):用于导航和操作对象图的OGML表达式,通过根对象和上下文中的变量来计算和求值。

通过组合根对象、上下文和表达式,可以使用OGML执行各种操作,如取值、设值等。

 

二、OGNL的基本操作

1、访问对象的属性

通过使用“.”(点号)运算符,可以访问对象的属性。

针对OGNL的Root对象的对象树的访问时通过“ . ”(点号)将对象的引用串联起来实现的。通过这种方式,OGNL实际上将一个树形的对象结构转化成一个链式结构的字符串来表达语义。

//获取Root对象中的name属性的值
name
//获取Root对象department属性中name属性的实际值
department.name
//获取Root对象department属性的manager属性中name属性的实际值
department.manager.name

 

2、访问上下文环境的

由于OGNL的上下文是一个Map结构,在OGNL进行计算时可以事先在上下文环境中设置一些参数,并让OGNL将这些参数带入进行计算。有时候也需要对这些上下文环境中的参数进行访问,访问这些参数时,需要通过“#”符号加上链式表达式来进行,从而表示与访问Root对象的区别。如下所示:

// 获取OGNL上下文环境中名为introduction的对象的值
#introduction
// 获取OGNL上下文环境中名为parameters的对象中user对象中名为name的属性的值
#parameters.user.name

 

3、调用对象的方法

通过使用“()”运算符,可以调用对象的方法。通过类似Java的方法调用方式进行,也就是通过“ . ”(点号)加方法名称完成方法调用,甚至可以传递参数。

// 调用Root对象中的group属性中users的size()方法
group.users.size()
// 调用Root对象中group中的containsUser的方法,并将上下文环境中名为requestUser的值作为参数传入
group.containsUser(#requestUser)

 

4、访问静态属性和方法

通过使用“@”符号(@[class]@[field / method] ),可以访问静态属性和方法。例如,假设有一个名为“Person”的类,它具有一个名为“NAME”的静态属性,可以使用“Person.NAME”来访问该属性。

// 访问com.example.core.Resource类中名为ENABLE的属性值
@com.example.core.Resource@ENABLE
// 调用com.example.core.Resource类中名为get的方法
@com.example.core.Resource@get()

 

5、使用操作符进行简单计算

OGNL表达式中能使用的操作符基本与Java里的操作符一样,除了能使用+、-、*、/、++、–、==等操作符之外,还能使用mod、in、not in 等。如下所示:

2 + 4  //
'hello' + 'world'  //字符串叠加
5 - 3  //
9 / 2  //
9 mod 2  // 取模
foo++  //递增
foo == bar  // 等于判断
foo in list  // 是否在容器中

 

6、对数组和容器的访问

OGNL表达式可以支持对数组按照数组下标的顺序进行访问。同样的方法可以用于有序的容器,如ArrayList、LinkedHashSet等。对于Map结构,OGNL支持根据键值进行访问。如下所示:

// 访问Root对象的group属性中users的第一个对象的name属性值
group.users[0].name
// 访问OGNL上下文中名为sessionMap的Map对象中key为currentLogonUser
#sessionMap['currentLogonUser']

 

7、投影与选择

OGNL支持类似于数据库中的投影(projection)和选择(selection)功能

投影操作是指选出集合中每个元素的相同属性组成新的集合,类似于关系数据库的字段操作。投影操作语法为 collection.{XXX} ,其中 XXX 就是这个集合中每个元素的公共属性。

选择就是过滤满足 selection 条件的集合元素,类似于关系数据库的结果集操作。选择操作的语法为: collection.{X YYY} ,其中 X 是一个选择操作符,后面则是选择用的逻辑表达式。选择操作符由三种:

  • ? 选择满足条件的所有元素

  • ^ 选择满足条件的第一个元素

  • $ 选择满足条件的最后一个元素

如下所示:

// 返回Root对象的group属性中users这个集合中所有元素的name构成的集合
group.users.{name}  // 新的以name为元素的集合
// 将group中users这个集合中的元素的code和name用-连接符拼起来构成的字符串集合
group.users.{code + '-' + name}  // 新的以'code-name'为元素的集合
// 返回Root对象的group中users这个集合所有元素中name不为null的元素构成的集合
group.users.{? #this.name != null}  // 过滤后的users集合

 

8、构造对象

OGNL支持直接通过表达式来构造对象。构造的方式主要包括3种:

  • 构造List: 使用 {} ,中间使用“ , ”(逗号)隔开元素的方式来表达列表

  • 构造Map:使用 #{} ,中间使用“ , ”(逗号)隔开键值对,并使用冒号隔开key和value来构造Map

  • 构造对象:直接使用已知对象的构造函数来构造对象

构造对象的方法如下所示:

// 构造一个List
{"green", "red", "blue"}
// 构造一个Map
#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}
// 构造一个java.net.URL对象
new java.net.URL("http://localhost/")

 

构造对象对于表达式语言来说是一个非常强大的功能,OGNL不仅能够直接对容器对象构造提供语法层面的支持,还能够对任意的Java对象提供支持。这样一来就使得OGNL不仅仅具备了数据运算这一简单的功能,同时还被赋予了潜在的逻辑计算功能。

 

9、深入this指针

我们知道,OGNL表达式是以“ . ”(点号)进行串联的一个链式字符串表达式。而这个表达式在进行计算的时候,从左到右,表达式每一次计算返回的结果成为一个临时的“当前对象”,并在此临时对象之上继续进行计算,直到得到计算结果。而这个临时的“当前对象”会被存储在一个叫做this的变量中,这个this变量就称为this指针。

在OGNL表达式中的this指针,无疑指向了当前计算的调用者对应的实例。 需要注意的是,如果试图在表达式中使用this指针,需要在this之前加上“#”,如下面例子:

// 返回group中users这个集合中所有age比3大的元素构成的集合
users.{? #this.age > 3}
// 返回group中users这个集合里的大小+1的值
group.users.size().(#this+ 1)
// 返回Root对象的group中users这个集合所有元素中name不为null的元素构成的集合
group.users.{? #this.name != null}

 

10、有关#符号的三种用途

在之前的要点中已经展示了“#”的几种不同用途。在这里在详细总结为:

  • 加在普通OGNL表达式前面,用于访问OGNL上下文中的变量

  • 使用 #{} 语法动态构建Map

  • 加在 this指针之前,表示对this指针的引用

 

posted @ 2024-02-01 17:09  r1-12king  阅读(53)  评论(0编辑  收藏  举报