`
zhaojin2012
  • 浏览: 6160 次
社区版块
存档分类
最新评论
  • 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百度百科OGNL百度百科

    OGNL百度百科OGNL百度百科OGNL百度百科OGNL百度百科OGNL百度百科OGNL百度百科

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

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

    OGNL 最初是为了能够使用对象的属性名来建立 UI 组件 (component) 和 控制器 (controllers) 之间的联系,简单来说就是:视图 与 控制器 之间数据的联系。后来为了应付更加复杂的数据关系,Drew Davidson 发明了一个...

    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.1.12-API文档-中文版.zip

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

    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文档-...

    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文档-...

    ognl表达式 ognl表达式

    ognl表达式 ognl表达式 ognl表达式 ognl表达式

    OGNL中文版详细文档

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

    ognl-3.1.12-API文档-中英对照版.zip

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

    ognl-2.6.11.jar 官方源码

    ognl-2.6.11.jar 源码 ognl-2.6.11.jar 源码

    struts2.0中的ognl

    基于WebWork核心的MVC开发与实践(ognl这一章)

    OGNL表达式的使用及文档

    关于OGNL表达式的使用的整理以及提供的文档说明,ps:文档说明是英文的,可能需要翻译

    ognl-3.0.5-sources.jar

    ognl-3.0.5源码 本人最近在研究s2sh源码,如有需要请留言。 在使用过程中如果有问题可联系,让我们开始学习s2sh源码总动员吧!

    Ognl在Struts2中的应用 源码

    本资源适合刚接触Struts和Ognl的小伙伴交流学习,欢迎吐槽。

    使用的ognl的chm

    使用的ognl,正对是struts2 hibernate 等

    ognl源码.rar

    ognl源码 ognl源码 ognl源码 ognl源码 ognl源码

    ognl.jar ognl.jar

    ognl.jar ognl.jar

    ognl-2.6.11.jar 的使用源码。EL语言的使用实例

    OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,...

Global site tag (gtag.js) - Google Analytics