与MVC框架解耦的OGNL:前世今生及其基本用法
来源:互联网 发布:苹果手机越狱软件 编辑:程序博客网 时间:2024/05/21 05:58
摘要:
虽然我们一般都是通过学习MVC框架而结缘OGNL,但它并没有与MVC框架紧紧耦合在一起,而是一个以独立的库文件出现的一种功能强大的表达式语言,也是字符串与Java对象之间沟通的桥梁。特别地,正因为它的独立性,使得我们可以十分方便地利用它构建我们自己的框架。在充分理解和掌握 OGNL 三要素 后,我们就可以通过简单一致的语法去存取Java对象树中的任意属性、调用Java对象树的方法并自动实现必要的类型转化。本文首先概述了Ognl的前世今生,并结合具体实例和源码阐述了OGNL的实质和OGNL三要素,介绍了对Java对象属性值的访问,静态、实例和构造方法的调用,对容器的访问以及对集合的操作等五个方面的介绍,奠定了学习OGNL的基础。
版权声明:
本文原创作者:书呆子Rico
作者博客地址:http://blog.csdn.net/justloveyou_/
友情提示:
为了更好地了解 OGNL,笔者将以两篇博客的篇幅来介绍OGNL:《与MVC框架解耦的OGNL:前世今生及其基本用法》 和 《再述OGNL:在Struts2中的应用》。其中,在本文(《与MVC框架解耦的OGNL:前世今生及其基本用法》)中,我们首先介绍了OGNL的前世今生,并结合具体实例和源码阐述了OGNL的实质、OGNL三要素和用法语法。在此基础上,本篇的姊妹篇《再述OGNL:在Struts2中的应用》详尽地介绍了OGNL的在Struts2中的应用。
一. OGNL 概述
1、OGNL的前世今生
WebWork是建立在称为XWork的Command模式框架之上的强大的基于Web的MVC框架。关于WebWork我们大多数人可能不太熟悉,最多只是有一种在哪里见过的感觉,但是我一提Struts2,估计大家就能想起来了。众所周知,Struts2是Struts的下一代产品,是在Struts1和WebWork的技术基础上进行了合并的全新框架。需要特别注意的是,全新的Struts2的体系结构与Struts1差别巨大,因为Struts2是以WebWork为核心的,继承了更多的WebWork血统。
实际上,WebWork 已经完全从Web层脱离出来的一个非常优秀的框架,其提供了很多核心的、Struts2还在使用的功能,包括前端拦截器(interceptor)、运行时表单属性验证、类型转换、IoC(Inversion of Control)容器等,其中就有我们今天的主角,强大的表达式语言 —— OGNL(Object Graph Notation Language)。
2、OGNL 带给我们的实惠
OGNL 是 Object Graph Navigation Language 的缩写,全称为 对象图导航语言,是一种功能强大的 表达式语言。它通过简单一致的语法,可以存取Java对象树中的任意属性、调用Java对象树的方法,并能够自动实现必要的类型转化。更形象地说,如果我们把OGNL表达式看做是一个带有语义的字符串,那么OGNL无疑是这个语义字符串与Java对象之间沟通的桥梁。
我们知道,在我们使用 MVC 架构模式进行开发Web应用时,数据往往需要在各层之间进行流转。由于数据在不同层次中的表现形式不尽相同,所以这种流转会很麻烦,特别是在Controller与View之间进行流转。实际上,数据在Controller层与View层之间流转的真正痛点就在于:数据在View层(视图页面)的表现形式是一个扁平的、不带任何数据类型的字符串,而在Controller层(Java世界)完全可以表现为一个具有丰富数据结构和数据类型的Java对象,正是由于这种数据表现形式的差异,导致我们手工执行这种转换将是一项非常复杂、低效的工作。正因为如此,为了更好地解决数据在不同层之间的数据流转问题,作为一个优秀成熟的框架,Struts2 集成了 WebWork 中的 OGNL 来帮助我们解决个问题。因此,当我们在使用Struts2时,会发现OGNL充斥在前后台数据传递与存储的方方面面,也给我们带来了极大的方便。
Ps:更多关于 MVC框架数据流转问题与OGNL在Web中的魅力 等内容请读者移步本文的姊妹篇《再述OGNL:在Struts2中的应用》。
3、小结
OGNL是模板语言的一个重要补充,对表现层技术而言是一次里程碑式的进步。在我们常见的视图组件,包括 Jsp 2.0,Velocity,Jelly 等,虽然都有类似的功能,比如,在 Jsp 2.0 中我们可以使用其提供的 EL 表达式完成类似的功能。但是,OGNL比它们要完善的多得多,而且以一个独立的库文件出现,十分方便我们构建自己的框架。
二. OGNL 深度解读:从一个例子说起
我们在上文已经提到,OGNL 以一个独立的库文件出现,十分方便我们构建自己的框架。那么,我们首先新建一个Java Project,然后从Struts2的相关依赖包中导入 ognl-x.x.xx.jar (本人使用的struts-2.1.6中的ognl-2.6.11.jar),搭建完毕后项目结构如下:
Ps:若读者不知如何重现笔者获取OGNL的jar包的过程,请笔者移步我的博文《Struts2 实战:从 登录Demo 看 Struts2 应用开发》去详细了解其获取过程,此不赘述。另外,由于OGNL是Apache开源项目的子项目,所以我们可以从 Apache Commons 下载OGNL的jar包。
1、OGNL应用实例
上述的Java Project包含两个JavaBean类和一个OGNL测试类,我们将围绕这个Project展开对OGNL的介绍。我们先看一下该Project中各个类的源码:
(1). 两个JavaBean
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
(2). OGNL测试类
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
上面的输出结果对我们来说一点也不意外,因为在Struts2中,我们常常使用上述方式访问Stack Context(Action Context)及其根对象Value Stack。根据这个例子我们也能够看出,所谓的对象图导航语言本质上就是通过 类似”放置到OgnlContext中的名字.属性名字” 的方式去获取对应对象的属性值。特别的是,对于根对象的属性的访问,我们只需直接利用属性名字访问即可,因为根对象只有一个,OGNL会默认从OgnlContext中的根对象中去寻找;而对于普通对象的属性的访问,我们使用类似”#放置到OgnlContext中的名字.属性名字”的方式去访问,这时OGNL在解析表达式的时候发现表达式开头带有”#”,就会去普通对象中去寻找。当然,使用这种方式也可以访问根对象的属性,但是若在访问普通对象时不加前缀“#”,将会抛出 ognl.OgnlException。
2、OGNL 三要素
事实上,OGNL表达式的计算是围绕OGNL上下文(OgnlContext)进行的,而OGNL上下文实际上就是一个Map对象。我们从上述的例子可以看出,无论是setValue方法还是getValue方法,它们均包含三个核心参数,即 tree(OGNL表达式), context(Ognl上下文), root(Ognl上下文的根对象),我们将其称之为 OGNL的三要素,因为 OGNL 的操作实际上就是围绕着这三个参数而进行的。这三者的关系如下图所示:
(1).表达式(Expression)
表达式是整个OGNL的核心,所有的OGNL操作都是对表达式解析后进行的。准确的来说,表达式表达了此OGNL操作的语义,即表明了此OGNL操作“要干什么”。
(2).上下文环境(Context)
我们在上文提到,所有的OGNL操作都是在一个特定的环境中进行的,这个环境就是OGNL的上下文环境(OGNL Context)。更直白地说,OGNL上下文为OGNL表达式的提供了具体的运行环境。需要指出的是,我们完全可以像操作Map那样将一些数据设置到OGNL Context中,以便我们通过OGNL访问。准确的来说,Context为OGNL表达式提供了具体环境,为OGNL操作“提供支持”。
(3).根对象(Root Object)
根对象是OGNL Context中的一员,并且整个OGNL Context最多只允许有一个根对象。也就是说,OGNL Context中共有两类对象,即 根对象 和 普通对象 ,它们的差异具体表现在访问方式上,我们针对根对象的存取操作的表达式不需要增加任何前缀(下文会具体提到)。根对象从侧面指明了OGNL操作所针对的对象类别,也就是说,在表达式规定了“干什么”之后,根对象指明了我们到底“对谁干”(根对象还是普通对象)。
3、OGNL源码解读
在上述的例子中,无论是setValue方法还是getValue方法,都是ognl.Ognl类提供的两个静态方法。事实上,在OGNL中,我们最常用到的两个类是 ognl.Ognl 与 ognl.OgnlContext 。ognl.Ognl类是一个抽象类,并提供了一系列用于解析和解释执行Ognl表达式的方法,而抽象类则是专门用来继承的;ognl.OgnlContext类则为Ognl表达式提供了一个执行环境,这个类实现了Map接口,所以允许我们通过使用Map的put(key,value)方法向OgnlContext添加各种类型的对象。需要注意的是,在OgnlContext中一共有两种对象,第一种是根对象,根对象在整个OgnlContext中有且最多只能有一个,我们可以通过调用OgnlContext.setRoot(obj)设置根对象。另外一种就是普通对象,它的个数不受限制。它们最重要的一个区别是在对象属性的获取方式上,前者可直接访问,后者需使用类似”#放置到OgnlContext中的名字.属性名字”的方式去访问 。下面给出了ognl.Ognl 与 ognl.OgnlContext 的声明方式,关于它们更多的细节本文不在赘述,读者若想进一步了解,请自行阅读源码。
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
Ps:关于 抽象类的深层次表述 请读者移步我的博文《Java 的抽象特性:抽象类与接口深度解析》。
4、小结
到此为止,我相信通过上面的例子和表述,我们对Ognl表达式有了一个更深入的了解和认识。此外,我们知道对于普通对象的属性的访问,我们只能使用类似”#放置到OgnlContext中的名字.属性名字”的方式去访问,而对于根对象的属性的访问,我们可以通过以下两种方式去访问:
直接利用属性名字访问;
类似”#放置到OgnlContext中的名字.属性名字”的方式去访问;
下文我们将着重讲述Ognl的基本用法,抛开MVC框架单独了解它的用法便于我们进一步理解Ognl在Struts2中的使用方式。
三. 使用 OGNL 去访问方法
我们除了利用Ognl表达式访问对象的属性,还可以使用它来访问方法。当然,对于方法的访问,又可以分为 对静态方法的访问、对实例方法的访问 和 对构造方法的访问,我们先看下面的例子:
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
四. 使用 OGNL 去访问容器对象
我们还可以利用Ognl表达式访问容器对象,包括数组,List,Set,Map等,看下面的例子:
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
由于Set是无序的且没有索引,所以我们只能对其进行迭代输出。Struts2 提供了一组逻辑控制标签,其中就有iterator,它可以完美完成这件事情。关于Struts2 的逻辑控制标签的叙述详见本文的姊妹篇《再述OGNL:在Struts2中的应用》。
由于HashSet就是通过HashMap实现的,所以更多关于 HashSet的了解,读者可以参考我的博文《Map 综述(一):彻头彻尾理解 HashMap》。
五. 使用 OGNL 对容器进行操作
我们还可以利用Ognl表达式对容器对象作一些操作,比如 过滤 和 投影。过滤指的是将原集合中不符合条件的对象过滤掉,然后将满足条件的对象,构建一个新的集合对象返回,Ognl过滤表达式的写法是:collection.{?|^|$ expression};投影指的是将原集合中所有对象的某个属性抽取出来,单独构成一个新的集合对象返回,基础语法为 :collection.{expression}。特别需要注意的是,无论是过滤操作还是投影操作,它们的操作对象和操作结果都是一个容器。
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 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
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
六. 总结
虽然我们一般都是通过学习MVC框架而结缘OGNL,但它并没有与MVC框架紧紧耦合在一起,而是一个以独立的库文件出现的一种功能强大的表达式语言,也是字符串与Java对象之间沟通的桥梁。特别地,正因为它的独立性,使得我们可以十分方便地利用它构建我们自己的框架。在充分理解和掌握 OGNL 三要素 后,我们就可以通过简单一致的语法去存取Java对象树中的任意属性、调用Java对象树的方法并自动实现必要的类型转化。本文首先概述了Ognl的前世今生,并结合具体实例和源码阐述了OGNL的实质和OGNL三要素,介绍了对Java对象属性值的访问,静态、实例和构造方法的调用,对容器的访问以及对集合的操作等五个方面的介绍,奠定了学习OGNL的基础。
七. 更多
更多关于 MVC框架数据流转问题与OGNL在Web中的魅力 等内容请读者移步本文的姊妹篇《再述OGNL:在Struts2中的应用》。
更多关于 抽象类的深层次表述 请读者移步我的博文《Java 的抽象特性:抽象类与接口深度解析》。
由于HashSet就是通过HashMap实现的,所以更多关于 HashSet的了解,读者可以参考我的博文《Map 综述(一):彻头彻尾理解 HashMap》。
- 与MVC框架解耦的OGNL:前世今生及其基本用法
- 与MVC框架解耦的OGNL:前世今生及其基本用法
- MES的前世与今生
- C#的前世与今生
- GC的前世与今生
- 四元数的“前世”与“今生”
- servlet、jsp和框架的前世今生
- Omi框架Store体系的前世今生
- karma 测试框架的前世今生
- 大话面向对象的前世与今生
- SOA与水果蛋糕的前世今生
- struts2与struts1的前世今生
- Kinect sdk与OpenNI的前世今生
- ssize_t与size_t的前世今生
- Kinect sdk与OpenNI的前世今生
- 支持向量机的前世与今生
- 堆和栈的前世与今生
- 支持向量机的前世与今生
- (六)IO库教程二--PCD文件操作
- 线程间通信/同步类容器和并发类容器
- 290. Word Pattern
- Criteria写没有映射字段的条件!可以用sql语句
- centos7中配置elasticsearch集群和离线安装x-pack
- 与MVC框架解耦的OGNL:前世今生及其基本用法
- LeetCode -- Add Two Numbers
- 2017.4.5所学
- B. Number Busters----数学推演
- Swoole 关于 HTTP SERVER 的事件顺序
- [树形DP] BZOJ 4013 [HNOI2015]实验比较
- RabbitMQ+PHP 消息队列环境配置
- 题目1156:谁是你的潜在朋友 九度OJ
- 冒泡排序,快速排序,归并排序