理解ValueStack的基本机制
ValueStack基础:OGNL(Object Graphic Navigation Language)
OGNL是Struts2中使用的一种表达式语言。它可以用于:
· 在JSP页面,使用标签方便的访问各种对象的属性;
· 在Action中获取传递过来的页面中的参数(并进行类型转换);
· 可以用在struts2的配置文件中!
所以,非常有必要理解OGNL的基本机制。
Root对象
OGNL称为对象图导航语言。
所谓对象图,即以任意一个对象为根,通过OGNL可以访问与这个对象关联的其它对象。
OGNL不支持多个root对象。
如:
- 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;
- }
- }
- 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;
- }
- }
- 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对象,及其相关的一系列对象:
- 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进行导航的代码如下:
- //利用OGNL表达式访问
- 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开始。
请看下面的例子:
- 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如下:
- 行1: <s:property value="username"/> <br/>
- 行2: <s:iterator value="#users">
- 行3: <s:property value="username"/>
- 行4: <s:property value="#root[2].username"/><br/>
- 行5: </s:iterator>
- 行6: <s:property value="username"/>
- 行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的基本机制的更多相关文章
- 理解ValueStack的基本机制 OGNL表达式
ValueStack基础:OGNL(Object Graphic Navigatino Language) OGNL是Struts2中使用的一种表达式语言. 它可以用于,在JSP页面,使用标签方便的访 ...
- 【转】深入理解 Java 垃圾回收机制
深入理解 Java 垃圾回收机制 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
- 深入理解java垃圾回收机制
深入理解java垃圾回收机制---- 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
- 我理解的Hanlder--android消息传递机制
每一个学习Android的同学都会觉得Handler是一个神奇的东西,我也一样,开始我以为我懂了Handler的机制,后来发现自己是一知半解,昨天想想,我能否自己实现一个Handler,让子线程与Ac ...
- 转:理解Cookie和Session机制
原文: 理解Cookie和Session机制 摘要: Cookie工作原理 由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份.怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论 ...
- 理解Cookie和Session机制
转载: 理解Cookie和Session机制 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录 ...
- <转>ASP.NET学习笔记之理解MVC底层运行机制
ASP.NET MVC架构与实战系列之一:理解MVC底层运行机制 今天,我将开启一个崭新的话题:ASP.NET MVC框架的探讨.首先,我们回顾一下ASP.NET Web Form技术与ASP.NET ...
- 深入理解 Java 垃圾回收机制
深入理解 Java 垃圾回收机制 一:垃圾回收机制的意义 java 语言中一个显著的特点就是引入了java回收机制,是c++程序员最头疼的内存管理的问题迎刃而解,它使得java程序员 ...
- iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...
随机推荐
- You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, i
[ERROR] Unknown lifecycle phase "mvn". You must specify a valid lifecycle phase or a goal ...
- LeetCode (32) Longest Valid Parentheses
题目 Given a string containing just the characters '(' and ')', find the length of the longest valid ( ...
- 【BZOJ 2761】 不重复数字 (哈希算法)
链接 http://www.lydsy.com/JudgeOnline/problem.php?id=2761 Description 给出N个数,要求把其中重复的去掉,只保留第一次出现的数. 例如, ...
- 实验:iscsi共享存储
实验名称: iscsi共享存储 实验环境: 我们需要准备一个磁盘,对于这个磁盘我们需要使用,将这个磁盘空间共享给iscsi客户端: 实验需求: 我们这里使用两台服务器来实现iscsi共享存储: 1.指 ...
- 【设计模式】GOF设计模式趣解(23种设计模式)
创建型模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说 ...
- 线段上的格点 辗转相除法(GCD)
/*问题描述:线段上的格点给定平面上的两个格点 P1 = (x1, y1) ; P2 = (x2, y2) 线段P1 P2上,除P1 和 P2以外一共有几个格点*//*分析过程在格点上画P1(0,5) ...
- 洛谷——P1546 最短网络 Agri-Net
P1546 最短网络 Agri-Net 题目背景 农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场.当然,他需要你的帮助. 题目描述 约翰已经给他的农场安排了一 ...
- strcpy c标准库函数
C语言标准库函数strcpy,把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间. 已知strcpy函数的原型是: char *strcpy(char *dst, const ...
- BZOJ4555求和(cdq分治+NTT)
题意: 输出f(n)对998244353(7 × 17 × 223 + 1)取模的结果.1 ≤ n ≤ 100000 其中S(i,j)是第二类Stirling数,即有i个球,丢到j个盒子中,要求盒子不 ...
- linux下查看哪个进程占用内存多
1.用top命令 1.top top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器 可以直接使用top命令后,查看%MEM的内容.可以 ...