目录
值栈概述
值栈是什么?
值栈(ValueStack),是struts2的数据中转站,栈中自动保存了当前Action对象和其他相关对象(包括常用的Web对象的引用。如request、session、application等),也可以手动保存自己的数据对象,同时也可以随时随地将对象从值栈取出或操作(通过OGNL表达式)
值栈,实际是一个接口对象的称呼,接口是ValueStack类,现实类是OgnlValueStack类,该对象是struts2利用ognl的基础,或者说Struts2中Ognl使用都是基于值栈完成的。
Struts2框架将ValueStack对象保存在request域中,键为“struts.valueStack”,即使栈是request域中的一个对象,一个请求对应一个Action实例和一个值栈对象。
值栈获取的方式
- 方式一:request.getAttribute("struts.valueStack");用的较少
- 方式二:ActionContext.getContext().getValueStack();用的非常多--底层使用的还是方式一获取
编写ValueStackAction1.java
public class ValueStackAction1 extends ActionSupport {
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
//获取值栈
//方式一:从request域中获取
ValueStack vStack1= (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
//方式二:通过ActionContext获取
ValueStack vStack2=ActionContext.getContext().getValueStack();
//获取的两次值栈是否是同一个对象?
System.out.println(vStack1==vStack2);
//当发出了两次请求(即运行两次action),两次情趣的值栈的hashcode不一致,表明每次请求都会重新创建值栈
System.out.println(vStack1.hashCode());
System.out.println(vStack2.hashCode());
return NONE;
}
}
配置struts.xml
<!-- 获取值栈的方式 -->
<action name="vs1" class="struts2_03.valueStack.ValueStackAction1"></action>
测试结果
【示例】(重点)
目标:通过断点查看值栈的内部存储结构。
查看值是存在值栈的哪里?
编写ValueStackAction2.java
public class ValueStackAction2 extends ActionSupport{
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
ValueStack valueStack=ActionContext.getContext().getValueStack();
//往值栈容器放数据
//使用push方式存储
valueStack.push("张艺兴");
valueStack.push("王一博");
valueStack.push("肖战");
//使用set方式存储数据(K-V)
valueStack.set("name", "小陈");
valueStack.set("age", "22");
//总结:使用push和set方法都会把数据放入root栈中
return NONE;
}
}
配置struts.xml
<!-- 查看值栈内部存储结构 -->
<action name="vs2" class="struts2_03.valueStack.ValueStackAction2"></action>
设置断点,进入debug模式
往下走发现
是栈结构,先进后出。
值栈里有一个root栈,继承ArrayList,List结构,以栈的方式去存
使用root栈来存数据时,取数据比较麻烦?使用Map来取数据比较方便
编写ValueStackAction3.java
public class ValueStackAction3 extends ActionSupport {
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
ActionContext context=ActionContext.getContext();
//通过put方式存储,放入map栈中
context.put("name", "王一博");
context.put("age", "22");
return NONE;
}
}
配置sruts.xml
<action name="vs3" class="struts2_03.valueStack.ValueStackAction3"></action>
设置断点,debug模式运行
总结
在值栈的内部有两个逻辑部分
ObjectStack(对象栈),由称为root栈,保存了Action的相关对象和动作,数据存储结构是List。
值栈操作(存值+取值)
值栈的存值机制
【回顾概念】
栈是一种数据结构,它按照先进后出的原则存储数据,即先进入的数据被压入栈底,最后进入的数据在栈顶,需要读取数据的时候,从栈顶开始弹出数据(即最后一个数据被第一个读出来)。
栈也被称为先进后出表,可进入插入和删除操作,插入称之为进栈(压栈)(push),删除称之为退栈(pop),允操作的一端称为栈顶(top),另外一端称为栈底(bottom)。栈底固定,而栈顶浮动。
对于栈只能每次访问它的栈顶元素。
值栈的取值机制
OgnlValueStack类包含两个重要的属性,一个root(CompoundRoot)和一个context(OgnlContext)。
OGNL Context是struts2的数据中心,其结构示意图为:
在这个OgnlContext对象中,有一个默认的顶层对象root(引用),俗称root栈,下面对象称之为Map栈。
对Ognl表达式的操作都是基于OgnlContext(map栈)对象,访问的规则如下:
- 如果访问root栈内容(CompoundRoot 对象栈内容),不需要#,直接通过元素的名称为访问。
- 如果访问Map栈内容(如request、response、session、servletContext、attr、patameters),需要#key来引用访问,例如#request.name相当于request.getAttribute("name")
编写ValueStackAction4.java
public class ValueStackAction4 extends ActionSupport
{
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
ValueStack stack=ServletActionContext.getContext().getValueStack();
stack.push("张艺兴");
stack.push("王一博");
//通过K-V形式把数据放入root栈中
stack.set("name", "肖战");
//通过map栈放数据
ActionContext.getContext().put("age", "28");
return SUCCESS;
}
}
配置struts.xml
<action name="vs4" class="struts2_03.valueStack.ValueStackAction4">
<result>/stack/valuestack.jsp</result>
</action>
编写valuestack.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>访问值栈</h3>
<h3>如何访问这个匿名对象呢?获取栈顶元素</h3>
<%-- <s:property value="[0].top"/> --%>
<s:property value="top"/>
<h3>如何还想获取第二个元素,如何获取呢?</h3>
<s:property value="[1].top"/>
<h3>获取第三个元素,如何获取呢?</h3>
<s:property value="[2].top"/>
<h3>获取map栈中的内容,要#</h3>
<s:property value="#age"/>
<h3>如何获取root栈中的有名字对象,不要#</h3>
<s:property value="name"/>
</body>
</html>
测试结果(访问vs4.action)
值栈的默认搜索
在实际开发中,使用Ognl表达式时,会经常用到值栈的默认搜索,即自动搜索值栈,找到所需要的值。
即单个数据直接放入root栈,如果有K-V形式的数据,则放入map栈。
不加#的情况下,先搜索root栈,如果没有,在搜索map栈
加#的情况下,直接搜索map
值栈的存钱小结
值栈的主要作用就是数据的保存和获取(可以在任何地方获取)
注意要点:怎么存,就怎么取
存进root栈,就不通过#获取<s:property value="xxx"/>
存进map栈,就通过#获取<s:property value="#xxx"/>
- 如何向值栈保存数据
- ValueStack.push(obj):保存数据到root栈顶-压栈(对象本身)-匿名
- ActionContex.getContext().put(key,value):保存数据到Map栈中
- ValueStack.set(key,value):将数据保存到root栈顶(数据对象自动被封装为Map来保存,栈顶是个map,map里面有个属性是对象)--有名字
- ognl表达式如何获取值栈的数据
jsp页面获取
1.<s:property value="name"/>先搜索roo栈对象属性(getter方法,getAxx-->xxx),再搜索map到key
2.<s:property value="#name"/>搜索map的key
3.通过[index].top,指定访问root栈某层对象,例如[0].top栈顶对象
Action代码获取
编写ValueStackAction5.java
public class ValueStackAction5 extends ActionSupport
{
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
//存root栈数据
ServletActionContext.getContext().getValueStack().set("username", "胡歌");
//取root数据
String string1= ActionContext.getContext().getValueStack().findString("username");
//存map栈数据
ActionContext.getContext().put("username", "刘亦菲");
//取map数据
String string2=ActionContext.getContext().getValueStack().findString("#username");
System.out.println("root栈"+string1+"--"+"map栈"+string2);
return NONE;
}
}
配置struts.xml
<action name="vs5" class="struts2_03.valueStack.ValueStackAction5"></action>
测试结果