valueStack(值栈)
值栈
值栈(ValueStack)就是 OGNL 表达式存取数据的地方。在一个值栈中,封装了一次请求所需要的所有数据。
在使用 Struts2 的项目中,Struts2 会为每个请求创建一个新的值栈,也就是说,值栈和请求是一一对应的关系,这种一一对应的关系使值栈能够线程安全地为每个请求提供公共的数据存取服务。
值栈的作用
值栈可以作为一个数据中转站在前台与后台之间传递数据,最常见的就是将 Struts2 的标签与 OGNL 表达式结合使用。
值栈实际上是一个接口,在 Struts2 中利用 OGNL 时,实际上使用的就是实现了该接口的 OgnlValueStack 类,这个类是 OGNL 的基础。
值栈的生命周期
值栈贯穿整个 Action 的生命周期,每个 Action 类的对象实例都拥有一个 ValueStack 对象,在 ValueStack 对象中保存了当前 Action 对象和其他相关对象。
Struts2 框架把 ValueStack 对象保存在一个名为 struts.valueStack 的 request 属性中,也就是说,值栈与 Action 的生命周期一致。值栈的生命周期随着 request 的创建而创建,随着 request 的销毁而销毁。
值栈的获取方式
要获取值栈中存储的数据,首先应该获取值栈。值栈的获取有两种方式:
● 在request中获取值栈:
ValueStack 对象在 request 范围内的存储方式为 request.setAttribute("struts.valueStack",valuestack),可以通过如下方式从 request 中取出值栈的信息。
//获取 ValueStack 对象,通过 request 对象获取
ValueStack valueStack = (ValueStack)ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
ServletActionContext.STRUTS_VALUESTACK_KEY 是 ServletActionContext 类中的常量,它的值为 struts.valueStack。
● 在ActionContext中获取值栈:
在使用 Struts2 框架时,可以使用 OGNL 操作 Context 对象从 ValueStack 中存取数据,也就是说,可以从 Context 对象中获取 ValueStack 对象。实际上,Struts2 框架中的 Context 对象就是 ActionContext。
ActionContext 获取 ValueStack 对象的方式:
//通过 ActionContext 获取 valueStack 对象
ValueStack valueStack = ActionContext.getContext().getValueStack();
ActionContext 对象是在 StrutsPrepareAndExcuteFilter 的 doFilter() 方法中被创建的,在源码中用于创建 ActionContext 对象的 createActionContext() 方法内可以找到获取的 ValueStack 对象的信息。
方法中还有这样一段代码:
ctx=new ActionContext(stack.getContext());
//stack.getContext()返回的是一个Map<String,Object>,根据此Map构造一个ActionContext
ValueStack 对象中的 Context 对象被作为参数传递给了 ActionContext 对象,这也就说明 ActionContext 对象中持有了 ValueStack 对象的引用,因此可以通过 ActionContext 对象获取 ValueStack 对象。
Struts2值栈内部结构详解
ValueStack 对象的内部有两个逻辑部分
● ObjectStack(root 栈):是 CompoundRoot 类型,用 ArrayList 定义,Struts2 把动作和相关对象压入 ObjectStack 中。
● ContextMap(Map 栈):是 OgnlContext 类型,是一个 Map 集合,Struts2 把各种各样的映射关系(一些 Map 类型的对象)压入 ContextMap 中。
通过运行项目查看 ValueStack 中的信息
首先,在 struts2Demo05 项目的 com.mengma.ognl 包中新创建一个名称为 ValueStackAction 的类,并在类中编写一个获取 ValueStack 对象的方法。
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;
public class ValueStackAction extends ActionSupport {
public String execute() throws Exception {
// 通过ActionContext获取valueStack对象
ValueStack valueStack = ActionContext.getContext().getValueStack();
System.out.println(valueStack);
return SUCCESS;
}
}
然后,将新建的 Action 信息添加到 struts.xml 中。
<action name="valueStack" class="com.mengma.ognl.ValueStackAction">
<result name="success">index.jsp</result>
</action>
最后,在 ValueStackAction 类中的第 11 行处设置断点,以 Debug 模式启动项目。在浏览器的地址栏中输入地址 http://localhost:8080/struts2Demo05/valueStack.action后,MyEclipse 会进入 Debug 模式。从 Variables 窗口中可以看到 valueStack 的结构信息。
如图所示的 ValueStack 结构中,只需关注 context 对象和 root 对象。从图中可以看到,context 对象的类型为 OgnlContext,root 对象的类型为 CompoundRoot。如果要查看这两个类的源码,则可以看到如下语句:
OgnlContext extends Object implements Map
CompoundRoot extends ArrayList
从上述两个类的源码中可以看出,context 对象实际上就是一个 Map,root 对象实际上就是一个 ArrayList。也就说明了 ValueStack 的两个逻辑部分 ObjectStack 对应 ArrayList(root),ContextMap 对应 Map(context)。
映射关系:
一般情况下,root 对象在存储 Action 的相关信息时会把相关的映射压入 ContextMap 中,这些相关的映射具体如下。
- parameters:该 Map 中包含当前请求的请求参数。
- request:该 Map 中包含当前 request 对象中的所有属性。
- session:该 Map 中包含当前 session 对象中的所有属性。
- application:该 Map 中包含当前 application 对象中的所有属性。
- attr:该 Map 按如下顺序检索某个属性:request,session,application。
需要注意的是,在 context 对象中包含了 root 对象,从 context 对象的结构中就可以查看到相关信息
从图中可以看到 context 对象中的 root 对象,这也就证明了 context 对象中包含了 root 对象,并且该对象的类型为 CompoundRoot。
Struts2获取值栈数据
在 Struts2 中,值栈的主要作用就是解决从 Action 到页面的数据交换问题。在采用属性驱动和模型驱动交换数据时,Struts2 会将对象自动存储到 ValueStack 中。
● 属性驱动:每次请求访问 Action 的对象时,Action 中的属性对象会被自动压入 ValueStack 中。
● 模型驱动:Action 如果实现了 ModelDriven 接口,那么 ModelDrivenInterceptor 拦截器会生效,会将 model 对象压入到 ValueStack 中。
属性对象或 model 对象存储到 ValueStack 中后,就可以直接从 ValueStack 中获取页面所需的数据。
属性驱动
1.创建实体类 User
创建一个名称为 User 的类,该类中包含 name 和 age 两个属性,以及其 getter 和 setter 方法。
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
创建 Action
创建一个名称为 ValueStack2Action 的类
import com.mengma.domain.User;
import com.opensymphony.xwork2.ActionSupport;
public class ValueStack2Action extends ActionSupport {
private static final long serialVersionUID = -6671554902053439423L;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String execute() throws Exception {
return SUCCESS;
}
}
声明了一个 User 类型的属性 user 及其 getter 和 setter 方法,由于只进行存取值的操作,所以直接使用 Action 的 execute() 方法返回 SUCCESS 即可。
修改配置文件
在配置文件 struts.xml 的 <package> 元素中,增加 action 的配置信息
<action name="valueStack2" class="com.mengma.ognl.ValueStack2Action">
<result>/field.jsp</result>
</action>
创建页面文件
在项目的 WebContent 目录下创建一个名称为 field.jsp 的文件
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>属性驱动方式获取值栈中的数据</title>
</head>
<body>
<s:debug></s:debug>
姓名:<s:property value="user.name"/><br/>
年龄:<s:property value="user.age"/>
</body>
</html>
编写了一个 <s:debug> 标签,用于查看值栈的信息,然后分别使用 <s:property> 标签获取用户的姓名和年龄。
启动项目并查看结果
从请求地址中传入的参数值已经成功地在页面中显示出来,这就是使用属性驱动获取 ValueStack 中对象的方式;
User 对象传入 Action 对象时,会被自动压入 ValueStack 中,所以在 Action 的 execute() 方法中不存储值也能在页面取出。
此时单击 Debug 标签链接便可以查看到值栈中的参数传递情况:
在参数列表中可以到 Property Name 列表中的参数 user 就是页面中获取的对象,在 Property Value 中包含了 user 的属性值。
模型驱动
采用模型驱动的方式时,Struts2 会将 Action 中的 model 信息存入到值栈中。
创建 Action
创建一个名称为 ValueStack3Action 的类
import com.alin.mengma.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class ValueStack3Action extends ActionSupport implements ModelDriven<User> {
private User user = new User();
@Override
public User getModel() {
return user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String execute() throws Exception {
return SUCCESS;
}
}
创建了一个 User 类型的对象 user,实现了 ModelDriven 接口的 getModel() 方法,并在 getModel() 方法中返回 user 对象,这样就可以接收到和 user 对象中属性名称相同的参数的值。
修改配置文件
在配置文件 struts.xml 的 <package> 元素中,增加 action 的配置信息
<action name="valueStack3" class="com.mengma.ognl.ValueStack3Action">
<result>/model.jsp</result>
</action>
创建页面文件
创建一个名称为 model.jsp 的页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>模型驱动方式获取值栈中的数据</title>
</head>
<body>
<s:debug></s:debug>
姓名:<s:property value="name"/><br/>
年龄:<s:property value="age"/>
</body>
</html>
启动项目并查看结果
从请求中传入的参数 name 和 age 已经成功地在页面中显示出来。由于是模型驱动,所以不需要用 user.name 的形式传递参数;
接下来单击 Debug 链接查看 ValueStack 中存储的参数值:
从下图中可以看出,采用模型驱动的方式时,User 对象的信息被存储在值栈的栈顶。由于 Action 中提供了一个 getModel() 方法,所以使用模型驱动时可以从 Action 中获取 model 对象,而在传递参数时,直接用 name 和 age 即可,这就是采用模型驱动获取值栈中数据的方式。
通过EL访问值栈的数据
在 Struts2 框架中,使用 EL 表达式也可以直接访问值栈中的数据。
<hr/>
使用EL表达式访问值栈中的数据:<br/>
姓名:${model.name }<br/>
年龄:${model.age }
使用了 EL 表达式获取值栈中的数据,重新访问页面后
直接用 EL 表达式的方式同样取出了值栈中的数据。EL 表达式能够访问值栈中数据的原因,是因为 Struts2 框架对请求进行了增强,如果在 request 作用域中没有查找到对应的值,就会到值栈中查找。查找时,它会先被当作属性在 root 中查找,查找不到再被当作 key 在 contextMap 中查找对应的 value,查找到后会将数据取出。
valueStack(值栈)的更多相关文章
- Struts 中 ActionContext ctx.put()把数据放到ValueStack里之数据传输背后机制:ValueStack(值栈)
1. 数据传输背后机制:ValueStack(值栈) 在这一切的背后,是因为有了ValueStack(值栈)! ValueStack基础:OGNL要了解ValueStack,必须先理解OGNL ...
- ValueStack值栈和ActionContext
Struts2在OGNL之上提供的最大附加特性就是支持值栈(ValueStack),在OGNL上下文中只能有一个根对象,Struts2的值栈则允许存在许多虚拟对象. 一:值栈(ValueStack) ...
- [ SSH框架 ] Struts2框架学习之三(OGNl和ValueStack值栈学习)
一.OGNL概述 1.1 什么是OGNL OGNL的全称是对象图导航语言( object-graph Navigation Language),它是一种功能强大的开源表达式语言,使用这种表达式语言,可 ...
- Struts2——(3)ValueStack(值栈)
一.ValueStack 主要用于存储请求相关信息,内部结构如下 root区:被称为根存储区,是一个栈结构,栈顶元素为当前请求的Action对象. context区:被称为变量存储区,是一个Map结构 ...
- [转]Struts2数据传输的背后机制:ValueStack(值栈)
1. 数据传输背后机制:ValueStack(值栈) 在这一切的背后,是因为有了ValueStack(值栈)! 2. ValueStack基础:OGNL 要了解ValueStack,必须先理解OGNL ...
- Struts2数据传输的背后机制:ValueStack(值栈)
1. 数据传输背后机制:ValueStack(值栈) 在这一切的背后,是因为有了ValueStack(值栈)! ValueStack基础:OGNL 要了解ValueStack,必须先理解OGN ...
- 【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
一.struts2系统验证 1.基于struts2系统验证的方式实际上就是通过配置xml文件的方式达到验证的目的. 2.实际上系统校验的方法和手工校验的方法在底层的基本实现是相同的.但是使用系统校验的 ...
- OGNL表示式使用和值栈
另外值得参考博客:http://blog.csdn.net/resigshy/article/details/7560573 OGNL是Object Graphic Navigation Langua ...
- [原创]java WEB学习笔记59:Struts2学习之路---OGNL,值栈,读取对象栈中的对象的属性,读取 Context Map 里的对象的属性,调用字段和方法,数组,list,map
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- JS 拷贝传值和引用传值
1.拷贝传值:基本数据类型都是“拷贝传值”. 拷贝传值,就是将一个变量的值“拷贝”一份,传给了另一个变量. 拷贝传值中,两个变量之间没有任何联系,修改其中一个变量的值,另一个不会改变. 这两个变量之间 ...
- STM32F4X 关于MDK上虚拟串口调试
1. 下载安装VSPD 自行百度安装后,利用VSPD将PC上的两个虚拟串口连接起来.如图我将COM1 和COM2连接起来. a. 点击Addr pair. 可以看到Virtual ports上将两个虚 ...
- XJOI夏令营501-511NOIP训练14——好朋友
传送门:QAQQAQ 题意:noip2011就要来了,W校的同学们不仅看重这次比赛,更看重noip2011和谁住在同一个房间.同学之间的关系好坏可以用一个亲密值表示,亲密值越大,两个同学关系越好.小A ...
- 用户管理模块之mysql.user
不使用-h参数来指定登录host,默认会连接localhost,仅当mysql.user表中有一条对应的localhost访问授权(username@%不对任何主机做限制也不行)时登录才成功,否则登录 ...
- JS流程控制语句 二选一 (if...else语句) 语法: if(条件) { 条件成立时执行的代码} else {条件不成立时执行的代码}
二选一 (if...else语句) if...else语句是在指定的条件成立时执行代码,在条件不成立时执行else后的代码. 语法: if(条件) { 条件成立时执行的代码} else {条件不成立时 ...
- JS规则 我还有其它用途( +号操作符)例如,算术操作符(+、-、*、/等),比较操作符(<、>、>=、<=等),逻辑操作符(&&、||、!)
我还有其它用途( +号操作符) 操作符是用于在JavaScript中指定一定动作的符号. (1)操作符 看下面这段JavaScript代码. sum = numa + numb; 其中的"= ...
- Mysql 数据库crash恢复
之前搭建的ghost博客比较坑,修改comment之后重启数据丢了,对node不熟悉,所以就切换回到wordpress了. 回滚快照之后发现数据库crash了,提示如下信息 2016-06-15 23 ...
- [JZOJ3168] 【GDOI2013模拟3】踢足球
题目 描述 题目大意 有两个队伍,每个队伍各nnn人. 接到球的某个人会再下一刻随机地传给自己人.敌人和射门,射门有概率会中. 每次射门之后球权在对方111号选手. 某个队伍到了RRR分,或者总时间到 ...
- 日志服务与SIEM(如Splunk)集成方案实战
背景信息 目标 本文主要介绍如何让阿里云日志服务与您的SIEM方案(如Splunk)对接, 以便确保阿里云上的所有法规.审计.与其他相关日志能够导入到您的安全运维中心(SOC)中. 名词解释 LOG( ...
- 0901NOIP模拟测试赛后总结
突然想学迪哥列一下分数线搞清楚自己和别人的差距. rank1- 5- 6-分. 差距很大啊.尤其是和某kyh.大家都开玩笑说天皇是个变态.但是事实摆在这儿,同样坐在机房这么长的时间,人家又AK了. 我 ...