`
zhaojin2012
  • 浏览: 6316 次
社区版块
存档分类
最新评论
  • Action-人生: 这都要感谢我们的张龙老师
    OGNL
  • dcljava: 写的蛮多的,挺好的,就是错别字稍微有点多,^_^
    OGNL

OGNL

    博客分类:
  • OGNL
阅读更多
Struts2  &  OGNL

OGNL(Object-Graph Navigation Language)对象图导航语言,struts2的OGNL基于java实现。

需要引入的OGNL jar
ognl-3.0.jar
javassist-3.7.ga.jar 这个包是上一个OGNL jar依赖的jar

struts2会调用相应的类和接口去解析我们在jsp页面中使用的ognl tags,所以以上两个包中的类都不是由我们自己直接调用的。
但是我们还是需要学习其中的类和接口,以便我们正常使用更放心。

OgnlContext(上下文对象):对应的是OgnlContext.class,他实现了java.util.map接口。那么就可以确定它里面的东西都是K/V对形式的封装;其二它存在唯一的叫做根的对象(root),可以通过程序设定上下文中当个对象作为根对象。
构造OgnlContext实例:
OgnlContext con = new OgnlContext();
//沿袭了map中的相应方法
con.put("person", person);//有一个POJO Person Dog
con.put("dog", dog);
con.setRoot(person);//将Person对象设置为上下文中唯一的root对象
Object obj = Ognl.parseExpression("name");//表示,能解析一个表达式(String arg0,这是该方法的参数,返回一个Object类型),这个方法的作用是,你给他一个String(参数),它就会根据这个String进行解析,
//Systout(obj); 测试解析出来的是什么~name,解析出来的还是name本身,而我们需要从OGNL Context中获取name属性的value,
Object obj2 = Ognl.getValue(obj, con, con.getRoot());//用于得到某一个具体的值,Param1代表解析之后的对象(Object obj = Ognl.parseExpression("name")中的obj对象),Param2表示上下文对象,Param3表示根对象,Returen一个Object。
//Systout(obj); (可以在Person Class定义中在相应的属性的getter方法中定义一个Systout,来测试相应的getter方法是不是会被调用。)测试~zhangsan(往POJO实例中设置的name值),这说明上面的Ognl.getValue方法所起的作用是,是从ognl上下文中根据表达式(Ognl.parseExpression("name");name就是表达式),找到具有name属性的对象,并且调用getter方法将Value取出来。但是它怎么知道我们需要的是Person的name呢?
Object obj3 = Ognl.parseExpression("#person.name");
//Systout(obj3); 测试~#person.name,又返回了字符串本身,
Object obj4 = Ognl.getValue(obj3, con, con.getRoot());
//Systout(obj4); 测试~zhangsan,输出了正确的我们所要的值,
Object obj5 = Ognl.parseExpression("#dog.name");
//Systout(obj5); 测试~#dog.name
Object obj6 = Ognl.getValue(obj5, con, con.getRoot());
//Systout(obj6); 测试~wangcai(在Dog对象中设置的name属性的值。)返回了我们所要的值,

通过上面的3次输出,来进行分析:

得出的结论,对于OGNL来说,如果你仅仅传递了一个属性的name,那么它就会到root对象中去找相应的name,我们上面把Person设置成了root对象,所以当我们直接传递name表达式的时候,Ognl对象就会直接到根对象中去找相应的getter(在这里是getName()方法),所以我需要为每一个POJO提供gettter方法。
如果我们需要寻找的属性(不是root对象的属性),我们需要上下文中其他对象的属性值怎么办?
那么在解析表达式的表达式编写上必须加上"#"井号,Ognl.parseExpression("#dog.name");,它表示,告诉Ognl对象,我们需找的不是root对象的属性,而是明确指定好的某一个对象的属性(在这里是dog对象的name属性),而对于根对象,我们同样可以使用"#",这种全称的形式,传递给Ognl对象进行解析,明确的告诉它,我们需要根对象的某个属性:Ognl.parseExpression("#person.name");,但是如果在Ognl.parseExpression这个方法中传递了一个非上下文中root对象所具有的属性,如:Ognl.parseExpression("numb");(numb随便起的一个属性,一个不存在的属性),那么Ognl在解析的时候,就找不到对应的getter方法,之后会抛出异常,ognl.NoSunckPropertyException.

对于我们在JSP页面中常用的类似下面这样的ognl标签,"#request.list"(之前在Action中往request中setAttribute了一个list属性),这个request就不是struts2中ognl上线文中的root object(根对象),所以前面加一个"#",告诉struts的Ognl对象,我们需要的是上下文中的非根对象request对象中的list属性,而这个request是struts ognl中为我们提供的命名对象中的一个,它其中还定义了下面这些上下文对象:
session/ application/ parameter
张龙:
在OGNL中,如果表达式没有使用#号,那么OGNL会从根对象中寻找该属性对应的get方法,如果寻找的不是根对象中的属性,那么则需要以#号开头,告诉OGNL,去寻找你所指定的特定对象中的属性。
demo:改变Person的定义:

在其中保持连接了一个Dog对象

在test中新建一个Dog实例dog2并设置到Person中,
这时root对象还是Person,那么我们需要寻找person对象中dog的name,就可以这样编写表达式:Ognl.parseExpression("dog.name");它会直接到root对象中去寻找Person中定义的getter方法(getDog),从中获取Person.dog.name的value,所以这里的dog不是上面new出来的那个dog2的name“dog2”.当然你也可以使用完全的限定名称:
Object obj7 = Ognl.parseExpression("#person.dog.name"); ~ #person.dog.name,sysout(Ognl.getValue(obj7, con, con.getRoot())); ~hello

》对于JDK中存在的大量的Class的定义中,都不符合JavaBean的标准,那么Ognl怎么对它们进行处理呢?
Ognl不单单可以使用getter取值,它也可以让我们直接操纵某一个对象的特定方法,下面就来分析。
沿袭上面的demo。
Object objN = ognl.parseExpression("name.toUpperCase() ")//需要注意oUpperCase()中的括号是不能省略的,上面的语句等价于"getname().toUpperCase()"只不过这个getter由Ognl帮助我们简化了,"name.toUpperCase() "这样我们root对象的name值就被转换成了大写的String,sysout(objN)~name.toUpperCase() 注意一点,解析表达式永远是返回表达式本身对象,sysout(Ognl.getValue(objN, con, con.getRoot())); ~ZHANGSAN被转换了!这样我们就使用了OGNL的对象图导航语言的调用对象方法的功能。我们还可以使用方法链的风格继续往后面累加相应适当的方法:"name.toUpperCase(). length()" ~8

》 我们还可以向表达式中的相应方法传递参数,而传递参数的过程,就和我们平常使用对象方法的时候是一样的,该怎么传递就怎么传递。
》使用OGNL调用类的静态方法:
在不生成对象的情况下,调用Java api中一些类的静态方法,我们使用Interger中的toBinaryString方法进行测试,该方法能将传递进去的int值转换成为一个二进制的字符串。
Object objN = Ognl.parseExperssion("@java.lang.Integer@toBinaryString(10)")//"@@"中间加上你想要调用的类的全称,将10转换成为2进制
sysout(objN)~name.toUpperCase()~@java.lang.Integer@toBinaryString(10)
sysout(Ognl.getValue(objN, con, con.getRoot())); ~1010,返回了10所对应的2进制数。
张龙:当使用OGNL调用静态方法的时候,需要按照如下语法编写表达式:
@package.classname@methodname(parameter)
对于OGNL来说,java.lang.Math是其的默认类(Math就是Ongl中的root对象),如果调用java.lang.Math的静态方法时,无需指定类的名字,比如:@@min(4, 10);

》访问一个Class的静态属性:
Ognl.parseExperssion("@@PI")//获取Meth Class中的静态字段PI
》生成一个对象
Object objN = Ognl.parseExperssion("new java.util.LinkedList()")//"
sysout(objN)~new java.util.LinkedList()
sysout(Ognl.getValue(objN, con, con.getRoot())); ~[],返回一个空的集合对象。因为集合的toString都是由一个[]中间包含各个元素的toString。
》生成对象的第2中方式:
以生成一个List对象为例:

使用getValue的重载的方法编写:
Object objN = Ognl.getValue("{'aa', 'bb', ...},cont,cont.getRoot()")//生成一个List对象,使用对象字面量的表达方式创建对象,“{}”中包含的集合元素,使用“,”逗号进行分隔不同的元素。
sysout(objN)~[aa,bb,....],直接输出了一个集合对象的toString。说明上面直接使用字面量的方式生成了一个集合对象。
》获取集合中的元素,在OGNL中集合和数字是一样的概念,就像Javascript中的数组。集合可以通过index索引来去访问。
Object objN = Ognl.getValue("{'aa', 'bb', ...}[2],cont,cont.getRoot()")//表示我们获取集合中的第二个元素bb。
sysout(objN)~bb
Object objN = Ognl.getValue("{'aa', 'bb'}[10],cont,cont.getRoot()")//如果我们访问一个越界的元素呢?和我们使用java访问数组越界是一样的道理,它会抛出异常:java,lang,IndexOutOfBoundsExceprion索引越界异常。
张龙:对于OGNL来说,数组与集合是一样的,都是通过下标索引来去访问的。构造集合的时候使用{ … }形式。

》在Dog Class 中添加一个数组对象,String[] friends:


在test中生成对应的dog对象并添加一个Friends数组:

dog对象已经放到Ognl上下文中了,可是并不是root object。

》访问dog中的属性值(数组的值)
Object objN = Ognl.getValue("#dog.friends", cont, cont.getRoot());
sysout(objN ); ~ [Ljava.lang.String.@da4453],输出了一个数组对象的toSting.
Object objN = Ognl.getValue("#dog.friends[1]", cont, cont.getRoot());//获取数组中的第二个对象。
sysout(objN ); ~ bb,bb是在friends[]中设置的值。正确的输出了。

》demo:将一个List对象放置到Ognl上下文中,在将其中的元素获取出来。

张龙:使用OGNL来处理映射(Map)的语法格式如下所示:
#{‘key1’: ‘value1’, ‘key2’: ‘value2’, ‘key3’: ‘value3’};
也使用对象字面量的表达式创建相应的集合。
》使用Ognl处理集合
sysout(Ognl.getValue("#{'key1':'value1', 'key2':'value2',...}", cont, cont.getRoot()));//~{key1=value1, key2=value1...}生成一个Map对象。
方位某一个具体的value:
sysout(Ognl.getValue("#{'key1':'value1', 'key2':'value2',...}['key2']", cont, cont.getRoot()));//~'value2获取对应的集合中的key2的value;
》过滤(filtering):collection.{? expression},可以获取被过滤的集合的符合过滤条件的子集合(新生成的集合,原来集合的子集合)。我们被过滤集合中的每一个子元素都会去匹配一次相应的表达式(条件)。



con.put("persons", persons);
Ognl.getValue("#persons.{? #thisname.length() > 4 }", cont, cont.getRoot());//"#persons"获取集合对象(collection.{? expression}中的collection),expression条件需要Person中name大于4。我们势必需要变量集合中的每一个元素,使之和表达式进行匹配,对于符合条件的将其放置到子集合中。最后返回符合条件的子集合。使用Ognl提供的“#this”关键字,在一个过滤操作中“#this”表示当前带操作的对象,我们需要遍历的集合中有多少元素,这个“#this”就会分别代表它们(相当于Iterator中的iter.next所获得的集合元素。类似增强的for循环,for(Person p : persons)中的p),第一次取出来的就是p1....以此类推。
张龙:在使用过滤操作时,我们通常都会使用#this,该表达式用于代表当前正在迭代的集合中的对象(联想增强的for循环)
现在的"#persons.{? #this.name.length() > 4 }"表示遍历集合对象,让每一个元素去取出它们的name属性的length长度,和“4”进行比较,如果符合这个表达式,就将其放入到新的子集中(Ognl.getValue返回一个Collections)。
sysout(Ognl.getValue("#persons.{? #thisname.length() > 4 }", cont, cont.getRoot()));//~ [com....,...],输出了集合的toString。

sysout(Ognl.getValue("#persons.{? #thisname.length() > 4 }.size()", cont, cont.getRoot()));//~ 输出子集的长度。
sysout(Ognl.getValue("#persons.{? #thisname.length() > 4 }.size"//这个和上面的一样,只不过是Ognl提供的伪属性,它自对于size()方法提供了该伪属性。实际上底层还是调用size()方法。而不是getSize()方法,所以我们不用去记伪属性,直接使用size()方法就行了。
张龙:OGNL针对集合提供了一些伪属性(如size,isEmpty),让我们可以通过属性的方式来调用方法(本质原因在于集合当中的很多方法并不符合JavaBean的命名规则),但我么你依然还可以通过调用方法来实现与伪属性相同的目的。
过滤(filtering),获取到集合中的第一个元素:collection.{^ expression}
8. 过滤(filtering),获取到集合中的最后一个元素:collection.{& expression}
sysout(Ognl.getValue("#persons.{? #this.name.length() > 4 }[0]", cont, cont.getRoot()));//~
sysout(Ognl.getValue("#persons.{^ #this.name.length() > 4 }", cont, cont.getRoot()));//~[con.....]
以上两种方式等价。但是需要注意的是,最终Ognl.getValue方法返回的还是一个子集,只不过是只有一个元素的子集。
sysout(Ognl.getValue("#persons.{& #this.name.length() > 4 }", cont, cont.getRoot()));//~返回最后一个元素

sysout(Ognl.getValue("#persons.{? #this.name.length() > 4 }[0].name", cont, cont.getRoot()));
sysout(Ognl.getValue("#persons.{^ #this.name.length() > 4 }[0].name", cont, cont.getRoot()));
sysout(Ognl.getValue("#persons.{^ #thisname.length() > 4 }.name", cont, cont.getRoot())); 这样是错误的,因为返回的是一个集合

》投影(projection):collection.{expression}
过滤与投影之间的差别:类比于数据库中的表,过滤是取行的操作,而投影是取列的操作。
对比过滤:过滤(filtering):collection.{? expression},过滤的子集中的元素,一定与原有集合中元素的属性的字段是不变的,而长度将会根据条件而变化。
而使用投影的话,返回的集合个数和原集合是不变的。
它们的区别在于,投影返回的集合长度不会改变,也就是说集合中的元素不会减少,但是返回的集合中的元素中的属性,是原来的元素中的属性的一个子集。
使用一张表作为参照,使用Ognl过滤,是在获取表中的行(列不变);使用投影,就是在去表中的列(行不变)。

张龙:过滤与投影之间的差别:类比于数据库中的表,过滤是取行的操作,而投影是取列的操作。
对于投影或者过滤都可以使用“#this”关键字。

我们现在获取每一个Person对象中name属性。
sysout(Ognl.getValue("#persons.{name}", cont, cont.getRoot()))//~ [zhangsan,....] ,返回了一个集合,里面有所有原集合中的等量元素,但是只有name属性。
"#persons.{name}" 返回一个集合
》加上条件,使用一个特定的值替换掉不匹配的属性的值。条件(name必须大于5),借助3元表达式。
sysout(Ognl.getValue("#persons.{#this.name.length() <= 5 ? 'Hello World' : #this.name}", cont, cont.getRoot())) //~[zhangsan,Hello World,...]
分享到:
评论
2 楼 Action-人生 2013-09-16  
这都要感谢我们的张龙老师
1 楼 dcljava 2012-07-12  
写的蛮多的,挺好的,就是错别字稍微有点多,^_^

相关推荐

    ognl.jar资源包

    camel-ognl-1.6.4.jar, camel-ognl-2.8.1.jar, com.springsource.org.ognl-2.6.9.jar, com.springsource.org.ognl-sources-2.6.9.jar, ognl-2.5.1.jar, ognl-2.6.11.jar, ognl-2.6.3.jar, ognl-2.6.5.jar, ognl-...

    ognl-3.2.21-API文档-中文版.zip

    赠送jar包:ognl-3.2.21.jar; 赠送原API文档:ognl-3.2.21-javadoc.jar; 赠送源代码:ognl-3.2.21-sources.jar; 赠送Maven依赖信息文件:ognl-3.2.21.pom; 包含翻译后的API文档:ognl-3.2.21-javadoc-API文档-...

    struts2.0中的ognl

    在Struts2中,OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取和设置对象属性,它在Struts2的核心组件中扮演着至关重要的角色。本篇文章将深入探讨OGNL在Struts2.0中的应用及其重要性。 ...

    ognl.jar(ognl-2.6.11.jar)

    标题中的“ognl.jar(ognl-2.6.11.jar)”指的是OGNL(Object-Graph Navigation Language)的特定版本,这是一个开源表达式语言,主要用于Java应用程序,它允许程序动态地访问和修改对象的属性。这个版本是2.6.11,表明...

    OGNL中文版详细文档

    OGNL特有的对象索引属性(Object Indexed Properties) 调用方法 变量引用 带括号的表达式 子表达式(Subexpressions)链 构造集合(Collection) 列表(Lists) 数组 映射表(Maps) 对集合的投影(Project) 在集合...

    OGNL表达式的使用及文档

    OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取和设置Java对象的属性。它被广泛应用于Spring框架和其他许多Java应用中,用于数据绑定和表达式评估。本篇将详细介绍OGNL的使用方法及其...

    ognl-2.6.11.jar 官方源码

    **ognl-2.6.11.jar 官方源码详解** OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取和设置Java对象的属性。它被广泛应用于许多Java框架,如Struts2,因为它允许动态地访问和操作对象的...

    struts2中的OGNL的源码

    其中,OGNL(Object-Graph Navigation Language)是Struts2中的核心表达语言,用于在视图层与模型层之间传递数据。在深入理解OGNL的源码之前,我们首先需要了解OGNL的基本概念和用法。 OGNL是一种强大的表达式语言...

    ognl表达式 ognl表达式

    ### OGNL表达式的理解和应用 #### 一、OGNL简介与基本概念 OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取和设置Java对象的属性。它是Struts2框架中的默认表达式语言,同时也被广泛...

    ognl表达式java使用案例详解(测试通过)

    本案例提供ognl使用详解,测试通过,只需解压放入自己WEB项目中,执行struts_ognl包内java文件即可(未提供jia包,若需要可以联系留言发至邮箱),若测试不好可以联系本人提供指导. Struts 2默认的表达式语言是OGNL...

    使用的ognl的chm

    **OGNL(Object-Graph Navigation Language)**是一种强大的表达式语言,主要用于获取和设置Java对象的属性。在Java开发中,尤其是Web应用框架如Struts2和Hibernate中,OGNL被广泛使用。它允许开发者以简洁的方式...

    OGNL教程,简单,看完懂OGNL语言

    OGNL,全称Object-Graph Navigation Language,是一种强大的表达式语言,主要用来获取和设置Java对象的属性。它的设计初衷是解决UI组件和控制器之间的数据绑定问题,使得视图和控制器之间的交互更为简便。随着时间的...

    ognl图形导航语言

    OGNL,全称为Object-Graph Navigation Language,是一种强大的开源表达式语言,主要用于便捷地操作对象的属性和方法。在Struts2框架中,OGNL作为默认的表达式语言发挥着核心作用,允许开发者以简洁的方式访问和修改...

    开发工具 ognl-3.1.12

    开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12开发工具 ognl-3.1.12...

    ognl的jar包

    OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,主要用在Java应用程序中,用于获取和设置对象的属性。它的设计目标是提供一种简洁、直观的方式来操纵对象图,包括对象的方法调用、属性访问以及...

    ognl源码和ognl帮助文档.rar

    OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,常用于Java应用,特别是Struts2框架中,用于数据绑定和动态方法调用。在这个压缩包中,包含的是OGNL的源码和帮助文档,这对于深入理解OGNL的工作...

    ognl-3.0.21.jar ognl.jar

    标题中的“ognl-3.0.21.jar”和“ognl.jar”是指OGNL(Object-Graph Navigation Language)的特定版本库文件。OGNL是一种强大的表达式语言,广泛用于Java应用程序,尤其是Web开发框架如Struts 2中,用于在模型、视图...

    ognl英文帮助文档

    OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,常用于Java应用程序,特别是与Struts2框架一起使用。它允许程序开发者通过简洁的语法来访问和操作对象的属性,执行复杂的逻辑,以及动态地构建...

    OGNL学习笔记,包含struts2中ognl的各种用法

    OGNL(Object-Graph Navigation Language)是Struts2框架中常用的一种表达式语言,用于在视图层方便地访问和操作模型数据。本篇笔记主要介绍了在Struts2中使用OGNL的一些基本用法。 首先,OGNL可以用来获取不同范围...

Global site tag (gtag.js) - Google Analytics