OGNL表达式介绍
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。 -------百度百科
从语言角度来说:它是一个功能强大的表达式语言,用来获取和设置 java 对象的属性 ,它旨在提供一个更高抽象度语法来对 java 对象图进行导航。另外,java 中很多可以做的事情,也可以使用 OGNL 来完成,例如:列表映射和选择。对于开发者来说,使用 OGNL,可以用简洁的语法来完成对 java 对象的导航。通常来说:通过一个“路径”来完成对象信息的导航,这个“路径”可以是到 java bean 的某个属性,或者集合中的某个索引的对象,等等,而不是直接使用 get 或者 set 方法来完成。
首先来介绍下OGNL的三要素:
一、表达式:
表达式(Expression)是整个OGNL的核心内容,所有的OGNL操作都是针对表达式解析后进行的。通过表达式来告诉OGNL操作到底要干些什么。因此,表达式其实是一个带有语法含义的字符串,整个字符串将规定操作的类型和内容。OGNL表达式支持大量的表达式,如“链式访问对象”、表达式计算、甚至还支持Lambda表达式。
二、Root对象:
OGNL的Root对象可以理解为OGNL的操作对象。当我们指定了一个表达式的时候,我们需要指定这个表达式针对的是哪个具体的对象。而这个具体的对象就是Root对象,这就意味着,如果有一个OGNL表达式,那么我们需要针对Root对象来进行OGNL表达式的计算并且返回结果。
三、上下文环境:
有个Root对象和表达式,我们就可以使用OGNL进行简单的操作了,如对Root对象的赋值与取值操作。但是,实际上在OGNL的内部,所有的操作都会在一个特定的数据环境中运行。这个数据环境就是上下文环境(Context)。OGNL的上下文环境是一个Map结构,称之为OgnlContext。Root对象也会被添加到上下文环境当中去。
OGNL 的基本语法:
1. 对Root对象的访问
OGNL使用的是一种链式的风格进行对象的访问。具体代码如下:
@Test
public void testOgnl()
{
User user = new User("rcx", "123");
Address address = new Address("110003", "沈阳市和平区");
user.setAddress(address);
try
{
System.out.println(Ognl.getValue("name", user));
System.out.println(Ognl.getValue("address", user));
System.out.println(Ognl.getValue("address.port", user)); //输出结果:
//rcx
//com.rcx.ognl.Address@dda25b
//
}
catch (OgnlException e)
{
e.printStackTrace();
}
}
2. 对上下文对象的访问
使用OGNL的时候如果不设置上下文对象,系统会自动创建一个上下文对象,如果传入的参数当中包含了上下文对象则会使用传入的上下文对象。当访问上下文环境当中的参数时候,需要在表达式前面加上'#',表示了与访问Root对象的区别。具体代码如下:
@Test
public void testOgnl1()
{
User user = new User("rcx", "123");
Address address = new Address("110003", "沈阳市和平区");
user.setAddress(address);
Map<String, Object> context = new HashMap<String, Object>();
context.put("init", "hello");
context.put("user", user);
try
{
System.out.println(Ognl.getValue("#init", context, user));
System.out.println(Ognl.getValue("#user.name", context, user));
System.out.println(Ognl.getValue("name", context, user));
//输出结果:
//hello
//rcx
//rcx
}
catch (OgnlException e)
{
e.printStackTrace();
}
}
这段代码很好的区分了访问Root对象和访问上下文对象的区别。
3. 对静态变量的访问
在OGNL表达式当中也可以访问静态变量或者调用静态方法,格式如@[class]@[field/method()]。具体代码如下:
public class Constant
{
public final static String ONE = "one"; public static void get()
{} public static String getString()
{
return "string";
}
} @Test
public void testOgnl2()
{
try
{
Object object = Ognl.getValue("@com.rcx.ognl.Constant@ONE", null); Object object1 = Ognl.getValue("@com.rcx.ognl.Constant@get()", null); Object object2 = Ognl.getValue("@com.rcx.ognl.Constant@getString()", null); System.out.println(object);
System.out.println(object1);
System.out.println(object2);
//one
//null 当返回值是void的时候输出的是null
//string
}
catch (OgnlException e)
{
e.printStackTrace();
}
}
4. 方法的调用
如果需要调用Root对象或者上下文对象当中的方法也可以使用.+方法的方式来调用。甚至可以传入参数。代码如下:
@Test
public void testOgnl3()
{
User user = new User();
Map<String, Object> context = new HashMap<String, Object>();
context.put("name", "rcx");
context.put("password", "password");
try
{
System.out.println(Ognl.getValue("getName()", context, user));
Ognl.getValue("setName(#name)", context, user);
System.out.println(Ognl.getValue("getName()", context, user));
//输出结果
//null
//rcx
}
catch (OgnlException e)
{
e.printStackTrace();
}
}
从代码可以看出来,赋值的时候可以选择上下文当中的元素进行给Root对象的name属性赋值。
5. 对数组和集合的访问
OGNL支持对数组按照数组下标的顺序进行访问。此方式也适用于对集合的访问,对于Map支持使用键进行访问。代码如下:
@Test
public void testOgnl4()
{
User user = new User();
Map<String, Object> context = new HashMap<String, Object>();
String[] strings = {"aa", "bb"};
ArrayList<String> list = new ArrayList<String>();
list.add("aa");
list.add("bb");
Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");
context.put("list", list);
context.put("strings", strings);
context.put("map", map);
try
{
System.out.println(Ognl.getValue("#strings[0]", context, user));
System.out.println(Ognl.getValue("#list[0]", context, user));
System.out.println(Ognl.getValue("#list[0 + 1]", context, user));
System.out.println(Ognl.getValue("#map['key1']", context, user));
System.out.println(Ognl.getValue("#map['key' + '2']", context, user));
//输出如下:
//aa
//aa
//bb
//value1
//value2
}
catch (OgnlException e)
{
e.printStackTrace();
}
}
从上面代码不仅看到了访问数组与集合的方式同时也可以看出来OGNL表达式当中支持操作符的简单运算。有如下所示:
2 + 4 //整数相加(同时也支持减法、乘法、除法、取余[ % / mod]、)
"hell" + "lo" //字符串相加
i++ //递增、递减
i == j //判断
var in list //是否在容器当中
6. 投影与选择
OGNL支持类似数据库当中的选择与投影功能。
投影:选出集合当中的相同属性组合成一个新的集合。语法为collection.{XXX},XXX就是集合中每个元素的公共属性。
选择:选择就是选择出集合当中符合条件的元素组合成新的集合。语法为collection.{Y XXX},其中Y是一个选择操作符,XXX是选择用的逻辑表达式。
选择操作符有3种:
? :选择满足条件的所有元素
^:选择满足条件的第一个元素
$:选择满足条件的最后一个元素
示例代码如下:
@Test
public void testOgnl5()
{
Person p1 = new Person(1, "name1");
Person p2 = new Person(2, "name2");
Person p3 = new Person(3, "name3");
Person p4 = new Person(4, "name4");
Map<String, Object> context = new HashMap<String, Object>();
ArrayList<Person> list = new ArrayList<Person>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
context.put("list", list);
try
{
ArrayList<Integer> list2 = (ArrayList<Integer>) Ognl.getValue("#list.{id}", context,
list);
ArrayList<String> list3 = (ArrayList<String>) Ognl.getValue("#list.{id + '-' + name}",
context, list);
ArrayList<Person> list4 = (ArrayList<Person>) Ognl.getValue("#list.{? #this.id > 2}",
context, list);
ArrayList<Person> list5 = (ArrayList<Person>) Ognl.getValue("#list.{^ #this.id > 2}",
context, list);
ArrayList<Person> list6 = (ArrayList<Person>) Ognl.getValue("#list.{$ #this.id > 2}",
context, list);
System.out.println(list2);
System.out.println(list3);
System.out.println(list4);
System.out.println(list5);
System.out.println(list6);
//[1, 2, 3, 4]
//[1-name1, 2-name2, 3-name3, 4-name4]
//[Person [id=3, name=name3], Person [id=4, name=name4]]
//[Person [id=3, name=name3]]
//[Person [id=4, name=name4]]
//
}
catch (OgnlException e)
{
e.printStackTrace();
}
}
7. 创建对象
OGNL支持直接使用表达式来创建对象。主要有三种情况:
构造List对象:使用{},中间使用','进行分割如{"aa", "bb", "cc"}
构造Map对象:使用#{},中间使用',进行分割键值对,键值对使用':'区分,如#{"key1" : "value1", "key2" : "value2"}
构造任意对象:直接使用已知的对象的构造方法进行构造。
示例代码如下:
@Test
public void testOgnl6()
{
try
{
Map<String, String> map = (Map<String, String>)Ognl.getValue("#{'key1':'value1'}", null);
System.out.println(map);
List<String> list = (List<String>)Ognl.getValue("{'key1','value1'}", null);
System.out.println(list);
Object object = Ognl.getValue("new java.lang.Object()", null);
System.out.println(object);
//{key1=value1}
//[key1, value1]
//java.lang.Object@dda25b
}
catch (OgnlException e)
{
e.printStackTrace();
}
}
补充:
表达式通常用来访问页面中的各种变量,进行结果输出.
struts2中共支持以下几种表达式语言(默认的是OGNL):
OGNL:可以方便地操作对象属性的开源表达式语言;
JSTL:(JSP Standard Tag Library):JSP2.0集成的标准表达式语言;
Groovy:基于Java平台的动态语言,它具有时下比较流行的动态语言的一些特性;
Velocity:一种基于Java的模板匹配引擎。
一、什么是OGNL
名称:全称是Object-Graph Navigation Language
用途:是一个用来获取 和设置 java对象属性的表达式语言。
应用场合:通过使用表达式语法导航对象图,而不是直接调用对象的获取和设置方法可以提供许多应用。比如在XML文件 或者脚本文件中嵌入OGNL表达式语法,在JSP页面 使用OGNL表达式语法。
操作对象:基于当前对象的上下文。
二、OGNL引用方式
属性名称:如对象user的属性username,可以使用user.username来获取.
方法调用:可以使用user.hashCode()返回当前对象的哈希码.
数组元素:对于userlist数组对象,可以使用userlist[0]来引用其中的某一个元素.
三、OGNL相对其他表达式语言具有下面几大优势
1)支持对象方法调用:如xxx.doSomeSpecial()
2)支持类静态的方法|值调用:格式为"@[类全名(包括包路径)]@[方法名|值名]"。如:
@java.lagn.String@format('foo%s','bar')--调用类静态方法
@tutorial.MyConstant@APP_NAME--访问类的静态值
3)支持赋值操作和表达式串联 :如price=100,discount=0.8,calculatePrice(),这个表达式会返回80
4)访问OGNL上下文 (OGNL context)和ActionContext
5)操作集合对象
四、使用OGNL表达式
1)要使用OGNL表达式,首先需要在web.xml中添加ActionContextCleanUp过滤器
<filter> <filter-name>struts-cleanup</filter-name> <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class> </filter> <filter-mapping> <filter-name>struts-cleanup</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
五、'#'运算符
用途一般有三种:
1)访问非根对象属性,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀 。实际上,#相当于ActionContext. getContext()。
parameters:包含当前HTTP请求参数的Map,#parameters.id[0],等价于request.getParameter("id");
request:包含当前HttpServletRequest的属性的Map,#request.userName,等价于request.getAttribute("username");
session:包含当前HttpSession的属性的Map,#session.userName,等价于session.getAttribute("username");
application:包含当前应用的ServletContext的属性的Map,#application.userName,等价于application.getAttribute("username");
attr:用于按request→session→application顺序访问某个属性,#attr.userName,等价于按顺序在request,session,application范围内读取userName属性,直到找到为止。
2)用于过滤和投影(projecting)集合
如person.{?#this.age>20}
? --获取集合中所有满足选择逻辑的对象(拿sql来做比例就是"select * from xxx where age>20")
^ --获取集合中第一个满足选择逻辑的对象(拿sql来做比例就是"select top(1) from xxx where age>20")
$ --获取集合中最后一个满足选择逻辑的对象
3) 用来构造Map
如#{'foo1':'bar1', 'foo2':'bar2'}
六、'%'运算符
用途是在标识的属性为字符串类型时,计算OGNL表达式的值,如:
<s:url value="test.jsp?age=#userlist['admin']">→test.jsp?#userlist['admin']---可见当字符串与OGNL表达式串起来时,只会被当作字符串对待,并不执行
<s:url value="test.jsp?age=%{#userlist['admin']}">→test.jsp?age=44---使用了该符号,就可以使得OGNL表达式被执行
七、'$'运算符
两个用途:
1)用于在国际化资源文件中,引用OGNL表达式。例如在资源文件中有一个标签fileName,则可以在资源文件中引用:
validation.require=${getText(fileName)} is required
2)在struts2配置文件中引用OGNL表达式,如:
<action name="AddPhoto" class="addPhoto">
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>--但这个albumId是从哪来的呢?
</action>
OGNL表达式介绍的更多相关文章
- (转)OGNL表达式介绍
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的表达式语法,可以存 ...
- [JavaWeb基础] 029.OGNL表达式介绍
1.OGNL概述 OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对 ...
- Struts2的OGNL表达式语言
一.OGNL的概念 OGNL是Object-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者 ...
- JSTL标签,EL表达式,OGNL表达式,struts2标签 汇总
一下纯属个人总结摘抄,总结一起方便查看,解决疑问,有遗漏或错误,还请指出. 1,JSTL标签总结: a).JSTL标签有什么用? JSTL是由JCP(Java Commu ...
- Struts标签、Ognl表达式、el表达式、jstl标签库这四者之间的关系和各自作用
我之前虽然会用,但是一直分不清彼此之间有什么区别,所以查找资料,将它们进行整合区分,加深了解, 一 介绍 1.Struts2的作用 Struts2标签库提供了主题.模板支持,极大地简化了视图页面的 ...
- 初窥struts2(二)OGNL表达式
Struts2总结 Struts2完整的处理流程: 1 客户端发送请求,交给struts2控制器(StrutsPrepareAndExecuteFilter). 2 Filter控制器进行请求过滤 ...
- Struts2之OGNL表达式
OGNL(Object-Graph Navigation Language的简称),对象图导航语言,它是一门表达式语言,除了用来设置和获取Java对象的属性之外,另外提供诸如集合的投影和过滤以及lam ...
- struts2 页面标签或ognl表达式取值--未完待续
一.加#号取值和不加#号取值的解说 1.s:property 标签——value属性使用事项 1)涉及问题:取值时什么时候该加#,什么时候不加? 2)介绍 <s:property value=& ...
- OGNL表达式的基本语法和用法
首先我们一起来看一下OGNL中的#.%和$符号. 关于OGNL各种用法总结参看:http://blog.163.com/seara520@126/blog/static/720693042010320 ...
随机推荐
- poj1035 Spell checker
这题目比较简单,把思路搞清楚就可以啦. #include <stdio.h> #include <string.h> +][]; int init(){ ; while(~sc ...
- Unable to add App ID because the '10' App ID limit in '7' days has been exceeded.
Unable to add App ID because the '10' App ID limit in '7' days has been exceeded. 官方的原因是对bundle iden ...
- 插入排序与shell排序(希尔排序)
1 .插入排序的过程如同我们平时打扑克牌取牌插入的过程,不断将取出的扑克牌插入已经排好的地方. 插入排序过程初始有序区间大小为1,取出无序区间的首元素,查找有序区间的合适位置,进行插入.不断重复上述过 ...
- 软件工程 speedsnail 第二次冲刺6
20150523 完成任务:碰撞墙壁,或线身体翻转: 遇到问题: 问题1 身体翻转与帧数冲突 解决1 运用循环嵌套解决 明日任务: 蜗牛碰到线后速度方向的调整
- 学习web前端开发感想
1.学习一个技术,不是一看见源代码就是copy,而是仔细阅读后,找到自己想要的,并且自己写出来,自己理解了,下次遇到同样的问题,自己才能解决. 2.在电脑上学习的过程中,我总是先建立一个文本文档,这样 ...
- php excel (转)
首先到phpexcel官网上下载最新的phpexcel类,下周解压缩一个classes文件夹,里面包含了PHPExcel.php和 PHPExcel的文件夹,这个类文件和文件夹是我们需要的,把clas ...
- mybatis使用笔记
关于动态SQL里的条件查询(if test): 1.lombok插件和mybatis插件在有些变量名下会冲突,比如一个变量为rType的字段,lombok插件认为应该是getRType,但是mybat ...
- javascript雪花效果 注释版
(function () { // 添加事件监听器 function addEvent(a, b, c) { if (a.addEventListener) a.addEventListener(b, ...
- ios view的frame和bounds之区别(位置和大小)
前言: 学习ios开发有一段时间了,项目也做了两个了,今天看视频,突然发现view的frame和bound两个属性,发现bound怎么也想不明白,好像饶你了死胡同里,经过一番尝试和思考,终于弄明白bo ...
- WPF学习03:Element Binding
元素绑定是数据绑定的一个子集,关于数据绑定是什么,园子里有很多文章都说得非常好,在此不予详细说明. WPF实现了完善的数据绑定机制,使得元素绑定有简易的实现步骤. 本文的元素指的是WPF中的可视控件. ...