ValueStack基础:OGNL(Object Graphic Navigation Language)

OGNL是Struts2中使用的一种表达式语言。它可以用于: 
  · 在JSP页面,使用标签方便的访问各种对象的属性; 
  · 在Action中获取传递过来的页面中的参数(并进行类型转换); 
  · 可以用在struts2的配置文件中! 
所以,非常有必要理解OGNL的基本机制。

Root对象

OGNL称为对象图导航语言。 
所谓对象图,即以任意一个对象为根,通过OGNL可以访问与这个对象关联的其它对象。 
OGNL不支持多个root对象。

如:

  1. package cn.com.leadfar.struts2.actions;
  2. public class User {
  3. private String username;
  4. private Group group;
  5. public String getUsername() {
  6. return username;
  7. }
  8. public void setUsername(String username) {
  9. this.username = username;
  10. }
  11. public Group getGroup() {
  12. return group;
  13. }
  14. public void setGroup(Group group) {
  15. this.group = group;
  16. }
  17. }
  1. package cn.com.leadfar.struts2.actions;
  2. public class Group {
  3. private String name;
  4. private Organization org;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public Organization getOrg() {
  12. return org;
  13. }
  14. public void setOrg(Organization org) {
  15. this.org = org;
  16. }
  17. }
  1. package cn.com.leadfar.struts2.actions;
  2. public class Organization {
  3. private String orgId;
  4. public String getOrgId() {
  5. return orgId;
  6. }
  7. public void setOrgId(String orgId) {
  8. this.orgId = orgId;
  9. }
  10. }

上面三个类,描述了通过一个User对象,可以导航到Group对象, 
进而导航到Organization对象。 
以User对象为根,一个对象图如下所示:

  1. User(root)
  2. -- username
  3. -- group
  4. -- name
  5. -- org
  6. -- orgId

在真实的环境下,这个对象图可能会极其复杂,但是通过基本的getters方法,都应该能够访问到某个对象的其它关联对象。 
【对象图的导航,必须通过getters方法进行导航】 
下述代码将创建一个User对象,及其相关的一系列对象:

  1. User user = new User();
  2. Group g = new Group();
  3. Organization o = new Organization();
  4. o.setOrgId("ORGID");
  5. g.setOrg(o);
  6. user.setGroup(g);

如果通过JAVA代码来进行导航(依赖于getters方法),导航到Organization的orgId属性,如下所示:

  1. //用JAVA来导航访问
  2. user.getGroup().getOrg().getOrgId();

【注意:导航的目的,是为了获取某个对象的值或设置某个对象的值或调用某个对象的方法!】 
【注意:OGNL表达式语言的真正目的,是为了在那些不能写JAVA代码的地方执行JAVA代码,或者是为了更方便地执行JAVA代码】 
利用OGNL进行导航的代码如下:

  1. //利用OGNL表达式访问
  2. String value = (String)Ognl.getValue("group.org.orgId", user);

Ognl.getValue()方法的第一个参数,就是一条OGNL表达式,第二个参数是指定在表达式中需要用到的root对象!

详细请参考官方的文档 
https://struts.apache.org/docs/ognl.html

__________________________________

言归正传 
__________________________________

ValueStack

Struts2是通过ValueStack来进行赋值与取值的。 
ValueStack实际上就是对OGNL的封装,OGNL主要的功能就是赋值与取值。

ValueStack中的数据,分两个部分存放:root和context 
同时ValueStack暴露相关的接口(赋值和取值): 
void setValue(String expr, Object value); 
Object findValue(String expr); 
通过OGNL表达式对ValueStack中的数据进行操作。

root

ValueStack中的root对象是CompoundRoot。 
CompoundRoot继承了ArraryList,提供了额外的方法:push()和pop()方法, 
用来对root对象中所包含的数据进行存取。 
正是通过这两个方法,CompoundRoot变成了一个栈结构. 
压栈操作,将导致对象被放到CompoundRoot的第0个元素上(第0个元素是栈顶),其它对象被依次往后移动; 
出栈操作,将导致CompoundRoot的第0个元素被移除(即栈顶元素被弹出),其它对象被依次往前移动

OGNL只能访问被压入堆栈(CompoundRoot)中的元素。 
在Struts2中,一个请求在最终到达Action的方法之前,Action对象本身会被压入 
ValueStack的CompoundRoot对象中。 
所以Action对象是CompoundRoot对象中的一个元素,可以使用OGNL表达式直接访问。

在jSP页面中,使用<s:property value=”ognl表达式”/>标签,将CompoundRoot栈中的值取出。 
在<s:property>标签中的OGNL表达式,最终会交给ValueStack来解释。 
比如:"username"就是一个OGNL表达式,意思是调用root对象的getUsername()方法。

Context

由于在OGNL中,不支持多个root对象,但在struts2的OGNL的表达式中, 
有可能需要访问到多个毫不相干的对象。这时候,我们把表达式中需要用到的对象放到Map中, 
传递给OGNL,进行访问。这个Map对象,称为context。

可见valueStack对OGNL进行了扩展,使OGNL表达式可以访问到多个root对象。

要在表达式中访问到context中的对象,需要使用“#对象名称”的语法规则。 
#表示将context对象的元素放入到CompoundRoot对象的栈顶。访问完后, 
context对象的元素会从栈顶移出,自动释放。

当CompoundRoot栈中存在多个不相干的root对象时,使用 #root[n]. 进行访问, 
n是root对象当前在栈中的顺序。从0开始。

请看下面的例子:

  1. public class UserAction {
  2. private String username;
  3. //查看用户的详细信息
  4. public String detail(){
  5. username = "张三";
  6. List list = new ArrayList();
  7. for(int i=0; i<10; i++){
  8. User user = new User();
  9. user.setUsername("User"+i);
  10. list.add(user);
  11. }
  12. ActionContext.getContext().put("users", list);
  13. User u = new User();
  14. u.setUsername("赵毅");
  15. ActionContext.getContext().getValueStack().push(u);
  16. return "detail";
  17. }

对应的JSP如下:

  1. 行1:  <s:property value="username"/> <br/>
  2. 行2:  <s:iterator value="#users">
  3. 行3:     <s:property value="username"/>
  4. 行4:     <s:property value="#root[2].username"/><br/>
  5. 行5:  </s:iterator>
  6. 行6:  <s:property value="username"/>
  7. 行7:  <s:property value="#root[1].username"/> <!-- 张三 -->

根据刚才的示例,我们知道,第1行的username是“赵毅”(因为JSP在执行这行代码的时候,CompoundRoot中有两个元素:第0个是“user对象赵毅”,第1个是“userAction对象张三”),因此第1行的username将取出CompoundRoot中第0个元素的username属性:赵毅

第2行代码是iterator标签,只定义了一个value属性,iterator标签将循环访问users这个List中的User对象,并把当前循环的user对象压入到CompoundRoot中!所以,在第3行和第4行代码被执行的时候,CompoundRoot中总共有3个元素:第0个元素是被iterator标签压入的当前循环的user对象;第1个元素是“user对象赵毅”;第2个元素是“userAction对象张三”,因此第3行代码的执行结果就是输出“UserX”,即当前循环的user对象的username属性!iterator标签将会依次取出List中的user对象,并不断压入/弹出user对象(每次循环,都将执行一遍压入/弹出)。而第4行代码取第2个元素的username属性,即userAction对象的username属性:张三。

第5行代码执行完成之后,在CompoundRoot中将剩下2个元素,与第2行代码被执行之前一样。所以,第6行代码的输出和第1行代码的输出结果是一样的,而第7行代码将取出userAction对象的username属性:张三

理解ValueStack的基本机制的更多相关文章

  1. 理解ValueStack的基本机制 OGNL表达式

    ValueStack基础:OGNL(Object Graphic Navigatino Language) OGNL是Struts2中使用的一种表达式语言. 它可以用于,在JSP页面,使用标签方便的访 ...

  2. 【转】深入理解 Java 垃圾回收机制

    深入理解 Java 垃圾回收机制   一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...

  3. 深入理解java垃圾回收机制

    深入理解java垃圾回收机制---- 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...

  4. 我理解的Hanlder--android消息传递机制

    每一个学习Android的同学都会觉得Handler是一个神奇的东西,我也一样,开始我以为我懂了Handler的机制,后来发现自己是一知半解,昨天想想,我能否自己实现一个Handler,让子线程与Ac ...

  5. 转:理解Cookie和Session机制

    原文: 理解Cookie和Session机制 摘要: Cookie工作原理 由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份.怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论 ...

  6. 理解Cookie和Session机制

    转载: 理解Cookie和Session机制 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录 ...

  7. <转>ASP.NET学习笔记之理解MVC底层运行机制

    ASP.NET MVC架构与实战系列之一:理解MVC底层运行机制 今天,我将开启一个崭新的话题:ASP.NET MVC框架的探讨.首先,我们回顾一下ASP.NET Web Form技术与ASP.NET ...

  8. 深入理解 Java 垃圾回收机制

            深入理解 Java 垃圾回收机制 一:垃圾回收机制的意义 java  语言中一个显著的特点就是引入了java回收机制,是c++程序员最头疼的内存管理的问题迎刃而解,它使得java程序员 ...

  9. iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...

随机推荐

  1. 剑指Offer(书):删除链表的节点

    题目:在O(1)的时间内删除列表节点. /** * 步骤: * 1.检查head与removeNode节点是否为空 * 2.检查removeNode的后一个节点是否为空,不为空则使用后一个节点的值覆盖 ...

  2. 南阳理工 58 最少步数 (DFS)

    描述 这有一个迷宫,有0~8行和0~8列: 1,1,1,1,1,1,1,1,1 1,0,0,1,0,0,1,0,1 1,0,0,1,1,0,0,0,1 1,0,1,0,1,1,0,1,1 1,0,0, ...

  3. Android GradientDrawable的XML实现

     Android GradientDrawable的XML实现 Android GradientDrawable与附录文章1类似,这次以XML而非Java代码形式实现.比如写好一个shape文件放 ...

  4. Sql Server数据库视图的创建、修改

    if OBJECT_ID('Sales.USACusts') is not null drop view Sales.USACusts; go create view Sales.USACusts a ...

  5. [luoguP2447] [SDOI2010]外星千足虫(高斯消元 + bitset)

    传送门 用bitset优化,要不然n^3肯定超时 消元过程中有几点需要注意,找到最大元后break,保证题目中所说的K最小 如果有自由元说明解很多,直接返回 #include <bitset&g ...

  6. [转]制作一个64M的U盘启动盘(mini linux + winpe +dos toolbox)

    自己动手定制winpe+各类dos工具箱U盘启动盘+minilinux 由于一个64M老U盘,没什么用,拿来发挥余热.如果U盘够大,可以使用功能更强大的mini linux和带更多工具的winpe.这 ...

  7. list如何remove

    http://blog.sina.com.cn/s/blog_621b6f0e0100s5n5.html 在java中对list进行操作很频繁,特别是进行list启遍历,这些操作我们都会,也很熟悉,但 ...

  8. 洛谷—— P1656 炸铁路

    P1656 炸铁路 题目描述 因为某国被某红色政权残酷的高压暴力统治.美国派出将军uim,对该国进行战略性措施,以解救涂炭的生灵. 该国有n个城市,这些城市以铁路相连.任意两个城市都可以通过铁路直接或 ...

  9. 寒武纪camp Day1

    补题进度:8/10 A(组合计数) 题意: 一个人站在数轴原点,每秒有1/4概率向前走一步,1/4概率向后走一步,1/2概率不动,问t秒后在p位置的概率. t,p<=100000 分析: 枚举不 ...

  10. jmete命令行停止失败的原因分析

    1.在jmeter的master机器上使用如下方式启动远程IP地址2.2.2.2,3.3.3.3上的jmeter slave服务,执行到最后生成报告: sh apache-jmeter-3.1/bin ...