`
jiaguwen123
  • 浏览: 414065 次
  • 性别: Icon_minigender_2
  • 来自: 深圳
社区版块
存档分类
最新评论

struts2中ognl表达式<一>

阅读更多
OGNL —— 完美的催化剂

         为了解决数据从View层传递到Controller层时的不匹配性,Struts2采纳了XWork的OGNL方案。并且在OGNL的基础上,构建了OGNLValueStack的机制,从而比较完美的解决了数据流转中的不匹配性。

         OGNL(Object Graph Navigation Language),是一种表达式语言。使用这种表达式语言,你可以通过某种表达式语法,存取Java对象树中的任意属性、调用Java对象树的方法、同时能够自动实现必要的类型转化。如果我们把表达式看做是一个带有语义的字符串,那么OGNL无疑成为了这个语义字符串与Java对象之间沟通的桥梁。

如何使用OGNL

让我们先研究一下OGNL的API,他来自于Ognl的静态方法:

Java代码 

/**  
* Evaluates the given OGNL expression tree to insert a value into the object graph  
* rooted at the given root object.  The default context is set for the given  
* context and root via <CODE>addDefaultContext()</CODE>.  
*  
* @param tree the OGNL expression tree to evaluate, as returned by parseExpression()  
* @param context the naming context for the evaluation  
* @param root the root object for the OGNL expression  
* @param value the value to insert into the object graph  
* @throws MethodFailedException if the expression called a method which failed  
* @throws NoSuchPropertyException if the expression referred to a nonexistent property  
* @throws InappropriateExpressionException if the expression can't be used in this context  
* @throws OgnlException if there is a pathological environmental problem  
*/  
public static void setValue( Object tree, Map context, Object root, Object value ) throws OgnlException  



我们可以看到,OGNL的API其实相当简单,你可以通过传递三个参数来实现OGNL的一切操作。而这三个参数,被我称为OGNL的三要素。



简单的API,就已经能够完成对各种对象树的读取和设值工作了。这也体现出OGNL的学习成本非常低。

在上面的测试用例中,需要特别强调进行区分的,是在针对不同内容进行取值或者设值时,OGNL表达式的不同。

Struts2 Reference 写道
The framework uses a standard naming context to evaluate OGNL expressions. The top level object dealing with OGNL is a Map (usually referred as a context map or context). OGNL has a notion of there being a root (or default) object within the context. In expression, the properties of the root object can be referenced without any special "marker" notion. References to other objects are marked with a pound sign (#).


上面这段内容摘自Struts2的Reference,我把这段话总结为以下2条规则:

A) 针对根对象(Root Object)的操作,表达式是自根对象到被访问对象的某个链式操作的字符串表示。
B) 针对上下文环境(Context)的操作,表达式是自上下文环境(Context)到被访问对象的某个链式操作的字符串表示,但是必须在这个字符串的前面加上#符号,以表示与访问根对象的区别。


    上面的这点区别咋看起来非常容易理解,不过一旦放到特定的环境中,就会显示出其重要性,它可以解释很多Struts2在页面展示上取值的各种复杂的表达式的现象。这一点在下一篇文章中会进行具体的分析。

OGNL三要素

我把传入OGNL的API的三个参数,称之为OGNL的三要素。OGNL的操作实际上就是围绕着这三个参数而进行的。

1. 表达式(Expression)

      表达式是整个OGNL的核心,所有的OGNL操作都是针对表达式的解析后进行的。表达式会规定此次OGNL操作到底要干什么。

我们可以看到,在上面的测试中,name、department.name等都是表达式,表示取name或者department中的name的值。OGNL支持很多类型的表达式,之后我们会看到更多。

2. 根对象(Root Object)

       根对象可以理解为OGNL的操作对象。在表达式规定了“干什么”以后,你还需要指定到底“对谁干”。

      在上面的测试代码中,user就是根对象。这就意味着,我们需要对user这个对象去取name这个属性的值(对user这个对象去设置其中的department中的name属性值)。

3. 上下文环境(Context)

     有了表达式和根对象,我们实际上已经可以使用OGNL的基本功能。例如,根据表达式对根对象进行取值或者设值工作。

      不过实际上,在OGNL的内部,所有的操作都会在一个特定的环境中运行,这个环境就是OGNL的上下文环境(Context)。说得再明白一些,就是这个上下文环境(Context),将规定OGNL的操作“在哪里干”。

         OGNL的上下文环境是一个Map结构,称之为OgnlContext。上面我们提到的根对象(Root Object),事实上也会被加入到上下文环境中去,并且这将作为一个特殊的变量进行处理,具体就表现为针对根对象(Root Object)的存取操作的表达式是不需要增加#符号进行区分的。

       OgnlContext不仅提供了OGNL的运行环境。在这其中,我们还能设置一些自定义的parameter到Context中,以便我们在进行OGNL操作的时候能够方便的使用这些parameter。不过正如我们上面反复强调的,我们在访问这些parameter时,需要使用#作为前缀才能进行。

OGNL与模板

    我们在尝试了OGNL的基本操作并了解了OGNL的三要素之后,或许很容易把OGNL的操作与模板联系起来进行比较。在很多方面,他们也的确有着相似之处。

对于模板,会有一些普通的输出元素,也有一些模板语言特殊的符号构成的元素,这些元素一旦与具体的Java对象融合起来,就会得到我们需要的输出结果。

而OGNL看起来也是非常的类似,OGNL中的表达式就雷同于模板语言的特殊符号,目的是针对某些Java对象进行存取。而OGNL与模板都将数据与展现分开,将数据放到某个特定的地方,具体来说,就是Java对象。只是OGNL与模板的语法结构不完全相同而已。

深入浅出OGNL

在了解了OGNL的API和基本操作以后,我们来深入到OGNL的内部来看看,挖掘一些更加深入的知识。

OGNL表达式

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

接下来我们就来看看一些常用的OGNL表达式:

1. 基本对象树的访问

对象树的访问就是通过使用点号将对象的引用串联起来进行。

例如:name,department.name,user.department.factory.manager.name

2. 对容器变量的访问

对容器变量的访问,通过#符号加上表达式进行。

例如:#name,#department.name,#user.department.factory.manager.name

3. 使用操作符号

OGNL表达式中能使用的操作符基本跟Java里的操作符一样,除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外,还能使用 mod, in, not in等。

4. 容器、数组、对象

OGNL支持对数组和ArrayList等容器的顺序访问:

例如:group.users[0]

同时,OGNL支持对Map的按键值查找:

例如:#session['mySessionPropKey']

不仅如此,OGNL还支持容器的构造的表达式:

例如:{"green", "red", "blue"}构造一个List,#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}构造一个Map

你也可以通过任意类对象的构造函数进行对象新建:

例如:new java.net.URL("http://localhost/")

5. 对静态方法或变量的访问

要引用类的静态方法和字段,他们的表达方式是一样的@class@member或者@class@method(args):

例如:@com.javaeye.core.Resource@ENABLE,@com.javaeye.core.Resource@getAllResources

6. 方法调用

直接通过类似Java的方法调用方式进行,你甚至可以传递参数:

例如:user.getName(),group.users.size(),group.containsUser(#requestUser)

7. 投影和选择



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

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

例如:group.userList.{username}将获得某个group中的所有user的name的列表。

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

例如:group.userList.{? #this.name != null}将获得某个group中user的name不为空的user的列表。

上述的所有的表达式,只是对OGNL所有表达式的大概的一个概括,除此之外,OGNL还有更多的表达式,例如lamba表达式等等。最具体的表达式的文档,大家可以参考OGNL自带的文档:

http://www.ognl.org/2.6.9/Documentation/html/LanguageGuide/apa.html

在撰写时,我也参考了potain同学的XWork教程以及一些网络上的一些文章,特此列出:

http://www.lifevv.com/java/doc/20071018173750030.html

http://blog.csdn.net/ice_fire2008/archive/2008/05/12/2438817.aspx

OGNLContext

    OGNLContext就是OGNL的运行上下文环境。OGNLContext其实是一个Map结构,如果查看一下它的源码,就会发现,它其实实现了java.utils.Map的接口。当你在调用OGNL的取值或者设值的方法时,你可能会自己定义一个Context,并且将它传递给方法。事实上,你所传递进去的这个Context,会在OGNL内部被转化成OGNLContext,而你传递进去的所有的键值对,也会被OGNLContext接管维护,这里有点类似一个装饰器,向你屏蔽了一些其内部的实现机理。

        在OGNLContext的内部维护的东西很多,其中,我挑选2个比较重要的提一下。一个是你在调用方法时传入的Context,它会被维护在OGNL内部,并且作为存取变量的基础依据。另外一个,是在Context内部维护了一个key为root的值,它将规定在OGNLContext进行计算时,哪个元素被指定为根对象。其在进行存取时,将会被特殊对待。

this指针

    我们知道,OGNL表达式是以点进行串联的一个字符串链式表达式。而这个表达式在进行计算的时候,从左到右,每一次表达式计算返回的结果成为当前对象,并继续进行计算,直到得到计算结果。每次计算的中间对象都会放在一个叫做this的变量里面这个this变量就称之为this指针。

例如:group.userList.size().(#this+1).toString()

在这个例子中,#this其实就是group.userList.size()的计算结构。

      使用this指针,我们就可以在OGNL表达式中进行一些简单的计算,从而完成我们的计算逻辑,而this指针在lamba表达式的引用中尤为广泛,有兴趣的读者可以深入研究OGNL自带的文档中lamba表达式的章节。

默认行为和类型转化

在我们所讲述的所有的OGNL的操作中,实际上,全部都忽略了OGNL内部帮助你完成的很多默认行为和类型转化方面的工作。

我们来看一下OGNL在进行操作初始化时候的一个函数签名:



/**  
* Appends the standard naming context for evaluating an OGNL expression  
* into the context given so that cached maps can be used as a context.  
*  
* @param root the root of the object graph  
* @param context the context to which OGNL context will be added.  
* @return Context Map with the keys <CODE>root</CODE> and <CODE>context</CODE>  
*         set appropriately  
*/  
public static Map addDefaultContext( Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map context );  
可以看到,在初始化时,OGNL还需要额外初始化一个类型转化的接口和一些其他的信息。只不过这些默认行为,由OGNL的内部屏蔽了。

一旦需要自己定义针对某个特定类型的类型转化方式,你就需要实现TypeConverter接口,并且在OGNL中进行注册。

同时,如果需要对OGNL的许多默认行为做出改变,则需要通过设置OGNL的全局环境变量进行。
分享到:
评论

相关推荐

    struts2 中 OGNL表达式的使用

    struts2 中 OGNL表达式的使用struts2 中 OGNL表达式的使用

    Struts2 使用OGNL表达式

    5. **上下文访问**:Struts2 ActionContext提供了一个全局上下文,可以在OGNL表达式中访问请求、session、application等范围的变量。 6. **值栈**:Struts2中的值栈是OGNL的主要工作区域,它存储了Action对象和其他...

    struts2 OGNL表达式

    Struts2 OGNL表达式是Java开发中一个重要的知识点,尤其在Web应用程序设计中扮演着核心角色。OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,它被Struts2框架广泛用于视图层与模型层之间的数据...

    struts2-OGNL表达式测试

    这个“struts2-OGNL表达式测试”可能是一个测试项目或代码示例,旨在演示如何在Struts2应用中使用OGNL表达式。 OGNL是Struts2的核心组件之一,它允许开发者通过简单的字符串表达式来获取或设置对象的属性。这使得视...

    struts2中ognl表达式的理解和用法

    OGNL表达式可以在一个上下文中执行,这个上下文包含了变量和对象。在Struts2中,Action上下文就是OGNL的默认上下文,其中包含了Action实例和其他请求相关的对象。 三、OGNL与Struts2的结合 1. 表单绑定:Struts2...

    ognl表达式 ognl表达式

    在Struts2中,OGNL的核心组件之一是`ValueStack`,它充当了OGNL表达式的数据源。`ValueStack`是一个存储数据的栈结构,包含了所有的模型对象以及请求、会话和应用范围的数据。开发者可以通过EL表达式直接访问`...

    struts2_OGNL表达式ActionContext及valuesStack

    首先,OGNL表达式是Struts2中不可或缺的一部分,它允许开发者以一种声明式的方式访问和修改对象的属性。比如,`myBean.getMyProperty()`这样的Java代码可以通过`#myBean.myProperty`的OGNL表达式在模板中实现。OGNL...

    Struts2 如何使用OGNL表达式(三十八)

    总结来说,Struts2中的OGNL表达式是连接模型和视图的关键工具,它提供了一种强大且灵活的数据访问和操作方式。通过熟练掌握OGNL,开发者可以更高效地构建和维护Struts2应用,同时要注意防止潜在的安全风险。在实际...

    精通struts2的ognl表达式

    ### 精通Struts2中的OGNL表达式 在深入探讨Struts2框架的核心功能时,理解并熟练掌握OGNL(Object-Graph Navigation Language)表达式的应用是至关重要的一步。OGNL是一种强大的表达式语言,它允许开发者通过简洁、...

    Struts2 OGNL示例(Maven项目)

    创建一个基于Maven的Struts2项目时,首先需要在`pom.xml`文件中配置相关的依赖,比如Struts2的核心库和OGNL库。这些依赖将确保在构建过程中自动下载并引入到项目中。例如: ```xml &lt;dependencies&gt; &lt;dependency&gt; ...

    struts2 ognl表达式

    Struts2 OGNL表达式是Java Web开发中一个重要的概念,它是一种强大的对象图形导航语言(Object-Graph Navigation Language)。在Struts2框架中,OGNL被广泛用于视图层,作为数据绑定的主要手段,使得开发者能够方便...

    OGNL表达式

    OGNL表达式作为一种强大且灵活的工具,极大地简化了Struts2框架中的数据访问和处理流程。通过对OGNL表达式的深入了解和掌握,开发者能够更加高效地构建复杂的Web应用程序,同时提高代码的可读性和可维护性。

    Struts2的标签库及OGNL表达式语言

    本篇文章将详细探讨Struts2中的OGNL表达式语言以及标签库。 **OGNL(对象图导航语言)** OGNL是一种强大的表达式语言,它允许开发者通过简洁的语法来访问和操作对象的属性。在Struts2框架中,OGNL扮演着至关重要的...

    Struts2 通过ognl表达式实现投影

    Struts2 框架中,OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,主要用于在 Struts2 应用程序中进行数据绑定和投影。OGNL 表达式可以用于过滤、投影和排序数据。 在 Struts2 中,OGNL 表达式...

    struts2 OGNL 表达式及各种标签的使用

    - 在Struts2的Action类中,可以使用OGNL表达式来动态地处理请求参数,如`String name = (String)params.get("user.name");` - 在JSP页面上,使用OGNL标签显示和处理数据,如`&lt;s:if test="%{user.isAdmin}"&gt;管理员...

    Strust2的if-else <tr></tr>用法

    以下是一个简单的示例,展示如何在Struts2中使用if-else控制`&lt;tr&gt;`标签的显示: ```jsp &lt;table&gt; &lt;s:iterator value="listOfObjects"&gt; &lt;% boolean displayRow = false; // 假设这是根据业务逻辑计算出的条件 %&gt; ...

    struts2 OGNL表达式使用

    struts2 OGNL表达式使用 OGNL(Object-Graph Navigation Language)是对象图导航语言,允许开发者在Struts2应用程序中访问和操作对象及其属性。下面是OGNL表达式的使用方法: 访问基本属性 1. 访问值栈中action的...

    Struts2深入学习----OGNL表达式原理

    Struts2是一个流行的Java Web...通过深入学习OGNL表达式原理,开发者能够更好地利用Struts2框架,提高Web应用的开发效率和可维护性。对于那些希望在Struts2开发中更进一步的人来说,熟悉和掌握OGNL是必不可少的技能。

    Struts2 OGNL表达式实例详解

    Struts2 OGNL表达式实例详解 Struts2 OGNL表达式实例详解主要介绍了Struts2 OGNL表达式实例详解,相关实例代码,需要的朋友可以参考。Object Graph Navigation Language(对象图导航语言),就是用点来访问成员变量...

    struts2中的OGNL的源码

    2. **AST节点(Abstract Syntax Tree Nodes)**:这些是解析过程的产物,每个节点代表OGNL表达式的一部分,如对象引用、属性访问或方法调用。 3. **值解析器(ValueResolver)**:负责实际的对象属性访问和方法调用...

Global site tag (gtag.js) - Google Analytics