1. 数据传输背后机制:ValueStack(值栈)

在这一切的背后,是因为有了ValueStack(值栈)!

2. ValueStack基础:OGNL

要了解ValueStack,必须先理解OGNL(Object Graphic Navigatino Language)!

OGNL是Struts2中使用的一种表达式语言,它可以:

①用于JSP的标签库中,以便能够方便的访问各种对象的属性;

②用于界面将参数传递到Action(并进行类型转换)中;

③用于struts2的配置文件中!

所以,非常有必要理解OGNL的基本机制。

2.1 Root对象

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

[+]view code

package cn.com.leadfar.struts2.actions;

 
public class User {
    private String username;
    private Group group;
  
    public String getUsername() {
       return username;
    }
    public void setUsername(String username) {
       this.username = username;
    }
  
    public Group getGroup() {
       return group;
    }
    public void setGroup(Group group) {
       this.group = group;
    }

}

[+]view code

package cn.com.leadfar.struts2.actions;

 
public class Group {
    private String name;
    private Organization org;
    public String getName() {
       return name;
    }
 
    public void setName(String name) {
       this.name = name;
    }
 
    public Organization getOrg() {
       return org;
    }
 
    public void setOrg(Organization org) {
       this.org = org;
    }

}

[+]view code

package cn.com.leadfar.struts2.actions;

 
public class Organization {
    private String orgId;
 
    public String getOrgId() {
       return orgId;
    }
 
    public void setOrgId(String orgId) {
       this.orgId = orgId;
    }

}

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

User(root)

-- username

-- group

-- name

-- org

-- orgId

在真实的环境下,这个对象图可能会极其复杂,但是通过基本的getters方法,都应该能够访问到某个对象的其它关联对象。【对象图的导航,必须通过getters方法进行导航

下述代码将创建一个User对象,及其相关的一系列对象:

[+]view code

User user = new User();

Group g = new Group();
Organization o = new Organization();
o.setOrgId("ORGID");
g.setOrg(o);

user.setGroup(g);

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

//用JAVA来导航访问

user.getGroup().getOrg().getOrgId();

【注意:导航的目的,是为了获取某个对象的值或设置某个对象的值或调用某个对象的方法!】

【注意:OGNL表达式语言的真正目的,是为了在那些不能写JAVA代码的地方执行JAVA代码,或者是为了更方便地执行JAVA代码】

利用OGNL进行导航的代码如下:

[+]view code

//利用OGNL表达式访问

String value = (String)Ognl.getValue("group.org.orgId", user);

Ognl.getValue()方法:

第一个参数,就是一条OGNL表达式;

第二个参数是指定在表达式中需要用到的root对象!

完整代码如下:

[+]view code

public void testOgnl01() throws Exception{

    User user = new User();
    user.setUsername("张三");
  
    //利用OGNL表达式访问user对象的username属性
    String value = (String)Ognl.getValue("username", user);
    log(value);
}
 public void testOgnl02() throws Exception{
    User user = new User();
    Group g = new Group();
    Organization o = new Organization();
    o.setOrgId("ORGID");
    g.setOrg(o);
    user.setGroup(g);
  
    //用JAVA来导航访问
    log(user.getGroup().getOrg().getOrgId());
  
    //利用OGNL表达式访问
    String value = (String)Ognl.getValue("group.org.orgId", user);
    log(value);
}
 public void testOgnl03() throws Exception{
    User user = new User();
    Group g = new Group();
    Organization o = new Organization();
    o.setOrgId("ORGID");
    g.setOrg(o);
    user.setGroup(g);
  
    //用JAVA来导航访问
    log(user.getGroup().getOrg().getOrgId());
  
    //也可以在表达式中使用#root来代表root对象
    String value = (String)Ognl.getValue("#root.group.org.orgId", user);
    log(value);
}
 private void log(Object o){
    System.out.println(o);

}

2.2 Context对象

在OGNL的表达式中,有可能需要访问到多个毫不相干的对象,这时候,我们需要给OGNL传递一个Map类型的对象,把表达式中需要用到的对象放到Map中即可!这个Map对象,称为context。

要在表达式中访问到context中的对象,需要使用“#对象名称”的语法规则。如:

[+]view code

public void testOgnl04() throws Exception{

       User user = new User();
       user.setUsername("张三");
   Group g = new Group();
   Organization o = new Organization();
   o.setOrgId("ORGID");
   g.setOrg(o);
   user.setGroup(g);
 
   User user2 = new User();
   user2.setUsername("李四");
 
   /**
* 所谓context其实就是一个Map类型的对象。主要是因为在OGNL中,不支持多个root对象,那么
* 如果需要在表达式中访问更多毫不相干的对象时,只能通过一个Map来把这些对象统一传递给OGNL。
*/
   Map context = new HashMap();
   context.put("u1", user);
   context.put("u2", user2);
 
   //在表达式中需通过“#+对象的名称”来访问context中的对象
   //如果表达式中没有用到root对象,那么可以用任意一个对象代表root对象!
   String value = (String)Ognl.getValue("#u1.username + ',' + #u2.username", context,new Object());
       log(value);
    }
  
    public void testOgnl05() throws Exception{
       User user = new User();
       user.setUsername("张三");
   Group g = new Group();
   Organization o = new Organization();
   o.setOrgId("ORGID");
   g.setOrg(o);
   user.setGroup(g);
 
   User user2 = new User();
   user2.setUsername("李四");
 
   User user3 = new User();
   user3.setUsername("王五");
 
   Map context = new HashMap();
   context.put("u1", user);
   context.put("u2", user2);
 
   //给OGNL传递root对象及context对象,以便解释对应的表达式
   String value = (String)Ognl.getValue("#u1.username + ',' + #u2.username + ',' + username", context,user3);
   log(value);

}

2.3 利用OGNL表达式进行赋值

OGNL表达式也可以用于赋值操作:

[+]view code

public void testOgnl06() throws Exception{

       User user = new User();
     
       //调用setValue()方法来进行赋值
       //第一个参数:OGNL表达式
       //第二个参数:root对象
       //第三个参数:要赋的值    
       Ognl.setValue("username", user, "张三");
 
       log(user.getUsername());
    }
  
    public void testOgnl07() throws Exception{
       User user = new User();
     
       Map context = new HashMap();
       context.put("u", user);
     
       //调用setValue()方法来进行赋值
       //第一个参数:OGNL表达式
       //第二个参数:context对象
        //第三个参数:root对象
       //第四个参数:要赋的值
       Ognl.setValue("#u.username", context, new Object(), "张三");
 
       log(user.getUsername());
    }
  
    public void testOgnl08() throws Exception{
       User user = new User();
     
       Map context = new HashMap();
       context.put("u", user);
      
       //利用赋值符号"="来进行赋值
       Ognl.getValue("#u.username = '李四'", context, new Object());
 
       log(user.getUsername());
    }
  
    public void testOgnl09() throws Exception{
       User user1 = new User();
       User user2 = new User();
       Map context = new HashMap();
       context.put("u1", user1);
       context.put("u2", user2);
     
       //在一个表达式中可以用逗号分隔,同时执行多个表达式
       Ognl.getValue("#u1.username = '李四',#u2.username='王五'", context, new Object());
 
       log(user1.getUsername());
       log(user2.getUsername());

}

2.4 利用OGNL调用对象的方法

[+]view code

//************************* OGNL调用对象的方法 *****************************//

    public void testOgnl10() throws Exception{
       User user = new User();
     
       //如果是调用root对象的方法,可以直接使用方法的名称来调用方法
       Integer value = (Integer)Ognl.getValue("addSomething(1,1)", user);
       log(value);
    }
  
    public void testOgnl11() throws Exception{
       User user = new User();
       user.setUsername("李四");
       //如果是调用root对象的方法,可以直接使用方法的名称来调用方法
       String value = (String)Ognl.getValue("getUsername()", user);
       log(value);
    }
  
    public void testOgnl12() throws Exception{
       User user = new User();
       Ognl.getValue("setUsername('王五')", user);
       String value = (String)Ognl.getValue("getUsername()", user);
       log(value);
    }
  
    //************************* OGNL调用静态方法和变量 *********************//
    public void testOgnl13() throws Exception{
       User user = new User();
       user.setUsername("王五");
       //调用静态变量
       //注意:out是System中的静态变量,out是PrintStream类型的一个对象
       //而println()则是out这个对象中的实例方法(不是静态方法)
       //调用静态方法,需要在类名和变量名前面加上@来调用,对于实例方法,用"."来调用
       Ognl.getValue("@System@out.println(username)", user);
    }
  
    public void testOgnl14() throws Exception{
       User user = new User();
       user.setUsername("wangwu");
       //调用静态方法,注意使用全路径类名
        Ognl.getValue("@System@out.println(@cn.com.leadfar.utils.Utils@toUpperCase(username))", user);

}

2.5 利用OGNL访问数组、集合对象

[+]view code

public void testOgnl15() throws Exception{

     
       Object root = new Object();
       Map context = new HashMap();
     
       //利用OGNL创建java.util.List对象
   List list = (List)Ognl.getValue("{123,'xxx','kdjfk'}", context, root);
   context.put("list", list);
 
   //利用OGNL创建数组
   int[] intarray = (int[])Ognl.getValue("new int[]{23,45,67}", context, root);
   context.put("intarray", intarray);
 
   //利用OGNL表达式创建java.util.Map对象
   Map mapvalue = (Map)Ognl.getValue("#{'listvalue':#list,'intvalue':#intarray}", context, root);
   context.put("mapvalue", mapvalue);
 
   //利用OGNL表达式访问这些数组和集合对象
   Ognl.getValue("@System@out.println(#list[1])", context,root);
   Ognl.getValue("@System@out.println(#intarray[2])", context,root);
   Ognl.getValue("@System@out.println(#mapvalue.listvalue[0])", context,root);
   Ognl.getValue("@System@out.println(#mapvalue['intvalue'][0])", context,root);
    }
  
    public void testOgnl16() throws Exception{
     
       List root = new ArrayList();
       User user1 = new User();
       user1.setUsername("张三");
   User user2 = new User();
   user2.setUsername("李四");
   root.add(user1);
   root.add(user2);
 
   //如果root对象是List类型
   log(Ognl.getValue("#root[0].username", root));
   log(Ognl.getValue("#root[1].username", root));

}

2.7 更多的特性,请参考官方的文档

OGNL官方文档地址:http://www.opensymphony.com/ognl/html/LanguageGuide/index.html

3. 应用:ValueStack

理解ValueStack的基本机制!对各种现象作出解释。

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

ValueStack是一个接口,而OgnlValueStack是strtus2中的缺省实现。ValueStack中的数据,分两个部分存放:root和context(这与OGNL中的概念一致),同时ValueStack暴露相关的接口:

void setValue(String expr, Object value);

Object findValue(String expr);

用来通过OGNL表达式对ValueStack中的数据进行操作!

ValueStack中的root对象是CompoundRoot,CompoundRoot继承了ArraryList,提供了额外的方法:push()和pop()方法,用来对root对象中所包含的数据进行存取!

[+]view code

public class CompoundRoot extends ArrayList {

    public CompoundRoot() {
    } 
    public CompoundRoot(List list) {
        super(list);
    }  
    public CompoundRoot cutStack(int index) {
        return new CompoundRoot(subList(index, size()));
    } 
    public Object peek() {
        return get(0);
    } 
    public Object pop() {
        return remove(0);
    }
    public void push(Object o) {
        add(0, o);
    }

}

正是通过这两个方法,CompoundRoot变成了一个栈结构!压栈操作,将导致对象被放到CompoundRoot的第0个元素上(第0个元素是栈顶),其它对象被依次往后移动;出栈操作,将导致CompoundRoot的第0个元素被移除(即栈顶元素被弹出),其它对象被依次往前移动!

OGNL不支持多个root对象,而struts2能够支持多个root对象,它对OGNL做了扩展。

如果某个OGNL表达式被传递给ValueStack(即调用ValueStack的setValue或findValue方法),而表达式中包含有对root对象的访问操作,ValueStack将依次从栈顶往栈底搜索CompoundRoot对象中所包含的对象,看哪个对象具有相应的属性,找到之后,立刻返回。

在Struts2中,一个请求在最终到达Action的方法之前,Action对象本身会被压入ValueStack(实际上就是放到ValueStack的CompoundRoot中),所以Action对象是CompoundRoot中的一个元素。看下面的代码:

[+]view code

public class UserAction {

    private String username;
    private Integer age;
    private boolean valid;
  
    //查看用户的详细信息
    public String detail(){
     
       username = "张三";
       age = 18;
       valid = true;
     
       return "detail";

}

在Action中,给Action的username/age/valid赋值。Detail页面如下:

[+]view code

username:<s:property value="username"/> <br/>

valid:<s:property value="valid"/> <br/>

age:<s:property value="age"/> <br/>

上述JSP页面将能正确将它们的值取出。<s:property value=”ognl表达式”/>。在s:property标签中的OGNL表达式,最终会交给ValueStack来解释。username就是一个OGNL表达式,意思是调用root对象的getUsername()方法。Struts2将自动搜索CompoundRoot中有哪些元素(从第0个元素开始搜索),检测这些元素是否有getUsername()方法,如果第0个元素没有getUsername()方法,将继续搜索第1、2、3……个元素是否有getUsername()方法。

在上面的例子中,CompoundRoot中只有一个对象,就是userAction对象,而这个对象中正好有getUsername()方法,所以,上述JSP代码将能够将值正确取出。

再看下面的例子:

[+]view code

public class UserAction {

    private String username;
    private String name;
  
    //查看用户的详细信息
    public String detail(){
       username = "张三";
       name = "王五";
     
       User u = new User();
       u.setUsername("赵毅");
       ActionContext.getContext().getValueStack().push(u);
     
       return "detail";

}

在上面这个UserAction的代码中,我们直接调用ActionContext.getContext().getValueStack().push()方法,把一个User对象(这个对象拥有getUsername()和setUsername()方法)直接压入到ValueStack中,这时候,在ValueStack的CompoundRoot中将有两个元素:第0个元素是刚刚压入的user对象[赵毅],而第1个元素是userAction对象[张三],如果在JSP中使用下面的表达式来取值:

<s:property value=”username”/> ,那么输出的值将是“赵毅”!道理上面已经讲过了,struts2将会从第0个元素开始搜索CompoundRoot中的对象,第0个元素正是刚刚压入的那个user对象!

如果在JSP中使用<s:property value=”name”/>来取值,将取出“王五”,因为第0个元素user对象没有name属性,所以,会继续搜索第1个元素userAction对象,在这个对象中就有name属性了!

再看下面的代码:

[+]view code

public class UserAction {

    private String username;
  
    //查看用户的详细信息
    public String detail(){
       username = "张三";
     
       List list = new ArrayList();
       for(int i=0; i<10; i++){
           User user = new User();
           user.setUsername("User"+i);
           list.add(user);
       }
       ActionContext.getContext().put("users", list);
     
       User u = new User();
       u.setUsername("赵毅");
       ActionContext.getContext().getValueStack().push(u);
     
       return "detail";

}

对应的JSP如下:

[+]view code

<s:property value="username"/> <br/>

<s:iterator value="#users">
    <s:property value="username"/>
    <s:property value="#root[2].username"/><br/>
</s:iterator>
<s:property value="username"/>

<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属性:张三

感谢有您,让我成长的更快:

Struts2数据传输的背后机制:ValueStack(值栈)

[转]Struts2数据传输的背后机制:ValueStack(值栈)的更多相关文章

  1. Struts2数据传输的背后机制:ValueStack(值栈)

    1.     数据传输背后机制:ValueStack(值栈) 在这一切的背后,是因为有了ValueStack(值栈)! ValueStack基础:OGNL 要了解ValueStack,必须先理解OGN ...

  2. Struts 中 ActionContext ctx.put()把数据放到ValueStack里之数据传输背后机制:ValueStack(值栈)

    1.     数据传输背后机制:ValueStack(值栈) 在这一切的背后,是因为有了ValueStack(值栈)! ValueStack基础:OGNL要了解ValueStack,必须先理解OGNL ...

  3. [ SSH框架 ] Struts2框架学习之三(OGNl和ValueStack值栈学习)

    一.OGNL概述 1.1 什么是OGNL OGNL的全称是对象图导航语言( object-graph Navigation Language),它是一种功能强大的开源表达式语言,使用这种表达式语言,可 ...

  4. ValueStack值栈和ActionContext

    Struts2在OGNL之上提供的最大附加特性就是支持值栈(ValueStack),在OGNL上下文中只能有一个根对象,Struts2的值栈则允许存在许多虚拟对象. 一:值栈(ValueStack) ...

  5. valueStack(值栈)

    值栈 值栈(ValueStack)就是 OGNL 表达式存取数据的地方.在一个值栈中,封装了一次请求所需要的所有数据. 在使用 Struts2 的项目中,Struts2 会为每个请求创建一个新的值栈, ...

  6. Struts2——(3)ValueStack(值栈)

    一.ValueStack 主要用于存储请求相关信息,内部结构如下 root区:被称为根存储区,是一个栈结构,栈顶元素为当前请求的Action对象. context区:被称为变量存储区,是一个Map结构 ...

  7. 【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】

    一.struts2系统验证 1.基于struts2系统验证的方式实际上就是通过配置xml文件的方式达到验证的目的. 2.实际上系统校验的方法和手工校验的方法在底层的基本实现是相同的.但是使用系统校验的 ...

  8. 框架学习之Struts2(三)---OGNL和值栈

    一.OGNL概述 1.1OGNL是对象图导航语言(Object-Graph Navigation Languaged)的缩写,他是一种功能强大的表达式语言,通过简单一致的表达式语法,可以存取Java对 ...

  9. struts2第三天——值栈

    大致内容: ognl概述 ognl入门 值栈 一.OGNL概述 OGNL,全称为Object-Graph Navigation Language,对象图导航语言 它是一个功能强大的表达式语言,用来获取 ...

随机推荐

  1. HDU4430 Yukari's Birthday(枚举+二分)

    Yukari's Birthday  HDU4430 就是枚举+二分: 注意处理怎样判断溢出...(因为题目只要10^12) 先前还以为要用到快速幂和等比数列的快速求和(但肯定会超__int64) 而 ...

  2. .net笔记

    一.垃圾回收 1.运行.NET应用程序时,程序创建出来的对象都会被CLR跟踪, 2.哪些对象还会被用到(存在引用关系):哪些对象不会再被用到(不存在引用关系),CLR都是有记录的. 3.CLR会整理不 ...

  3. 在AWS中创建NAT节点

    NAT, Network Address Translation,即网络地址转换.当内部网络的主机想要访问外网,但是又不想直接暴露给公网,可以通过NAT节点来访问外网.这样做有两个好处,第一是内网的主 ...

  4. Linux网络编程系列-套接口选项控制

    获取和设置套接口选项的方法有: getsockopt/setsockopt fcntl ioctl getsockopt/setsockopt 这两个函数仅用于套接口(socket)的设置,另外两个函 ...

  5. IOS UIView 03- 自定义 Collection View 布局

    注:本人是翻译过来,并且加上本人的一点见解. 前言 UICollectionView 在 iOS6 中第一次被引入,也是 UIKit 视图类中的一颗新星.它和 UITableView 共享一套 API ...

  6. ios 向工程里添加Fonts

    ios 向工程里添加Fonts 1.网上搜索字体文件(后缀名为.ttf,或.odf),假如你加入的字体为微软雅黑 2.把字体库导入到工程的resouce中 3.然后在你的工程的Info.plist文件 ...

  7. String的length()和Array的length

    String是个final修饰的最终类,不能被继承,String中属性都设置为private,方法为public,并不提供set方法,想要获得字符串的长度必须调用length()方法这个长度是确定的, ...

  8. 品味FastDFS~目录

    回到占占推荐博客索引 参考文献:http://baike.baidu.com/view/973383.htm#sub5143372 分布式文件系统(DFS,Distributed File Syste ...

  9. Atitit  基于meta的orm,提升加速数据库相关应用的开发

    Atitit  基于meta的orm,提升加速数据库相关应用的开发 1.1. Overview概论1 1.2. Function & Feature功能特性1 1.2.1. meta api2 ...

  10. 每天一个linux命令(38):cal 命令

    cal命令可以用来显示公历(阳历)日历.公历是现在国际通用的历法,又称格列历,通称阳历."阳历"又名"太阳历",系以地球绕行太阳一周为一年,为西方各国所通用,故 ...