九、Struts2的值栈

概述

值栈就相当于Struts2框架的数据的中转站,向值栈存入一些数据。从值栈中获取到数据。
ValueStack 是 struts2 提供一个接口,实现类 OgnlValueStack ---- 值栈对象 (OGNL是从值栈中获取数据的 )。
Action是多例的,有多少请求,就创建多少Action实例,每一个Action会创建一个ActionContext对象,代表的是Action的上下文对象,同时还会创建一个ValueStack对象。
每个Action实例都有一个ValueStack对象 (一个请求 对应 一个ValueStack对象 ),在其中保存当前Action 对象和其他相关对象
Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中 (值栈对象 是 request一个属性)

上面概述中提到了OGNL,这里做下解释
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写, 所谓对象图,即以任意一个对象为根,通过OGNL可以访问与这个对象关联的其它对象,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性;
Struts2框架使用OGNL作为默认的表达式语言,OGNL是一种比EL强大很多倍的语言,Struts2的核心包中已经包含ognl的jar包,例如ognl-3.0.6.jar.


值栈的内部结构

值栈由两部分组成,root栈和context栈

  • root: Struts把动作和相关对象压入ObjectStack 中, 内部是ArrayList数据结构。
  • context :Struts把各种各样的映射关系(一些 Map 类型的对象) 压入ContextMap中,内部是Map数据结构,
    Struts2会默认把下面这些映射压入ContextMap(context)中:
    • parameters: 该 Map 中包含当前请求的请求参数 ?name=xxx&password=123
    • request: 该 Map 中包含当前 request 对象中的所有属性
    • session: 该 Map 中包含当前 session 对象中的所有属性
    • application:该 Map 中包含当前 application 对象中的所有属性
    • attr: 该 Map 按如下顺序来检索某个属性: request, session, application

其中parameters、request、session、application和attr将作为context栈中的Map的key。

另外,root栈中的值只能在请求转发中取出,无法在重定向后取出,而context栈中的值在请求转发或者重定向都可以取出。

注意:
在jsp页面中使用OGNL表达式取值的时候,root栈和contex栈的取值有点不同

访问root栈中数据时,不需要写#

访问context栈中的request、 session、application、 attr(从最小域开始搜索)、 parameters(请求参数) 对象数据必须写 #


值栈和ActionContext对象的关系

值栈对象是请求时创建的, ActionContext是绑定到当前的线程上,那么在每个拦截器或者Action中获取到的ActionContext是同一个。
通过ActionContext可以获取到值栈对象(ValueStack),例如:
ValueStack vs = ActionContext.getContext().getValueStack();


root栈保存数据

ValueStack提供2个方法保存root栈的数据
1.push方法
valueStack.push(Object obj);
push方法把数据保存到root栈的栈顶位置,root栈是一个ArrayList集合,push方法源码如下:

 	public void push(Object o) {
        root.push(o); //其中root是一个CompoundRoot,它是继承ArrayList的
    }

2.set方法
valueStack.set(String key, Object obj);
set方法保存数据会先将数据保存到内部的map集合,map的key就是该方法参数的key, map的value就是该方法参数的obj, 然后再将该map集合添加到root栈的栈顶位置,源码如下:

/**
     * @see com.opensymphony.xwork2.util.ValueStack#set(java.lang.String, java.lang.Object)
     */
    public void set(String key, Object o) {
        Map setMap = retrieveSetMap(); //获取一个内部的map集合
        setMap.put(key, o);//保存数据
    }

    private Map retrieveSetMap() {
        Map setMap;
        Object topObj = peek();//获取栈顶的数据
        if (shouldUseOldMap(topObj)) { //判断栈顶数据是否是map集合
            setMap = (Map) topObj;//是则强转为map
        } else {
            setMap = new HashMap(); //不是则new一个map
            setMap.put(MAP_IDENTIFIER_KEY, "");
            push(setMap);//通过push方法,将map保存到roo栈的栈顶
        }
        return setMap;//返回该map的引用
    }
  /**
     * check if this is a Map put on the stack  for setting if so just use the old map (reduces waste)
     */
    private boolean shouldUseOldMap(Object topObj) {
        return topObj instanceof Map && ((Map) topObj).get(MAP_IDENTIFIER_KEY) != null;
    }

提示:
root栈中存入对象的话,优先使用push方法;存入集合的话,优先要使用set方法。


context栈保存数据

valueStack没有提供直接操作context栈的方法,但是可以通过其他对象来将数据保存到context栈中,例如上面提到的request/session/application域对象,调用其setAttribute方法,其实就是将数据保存到context栈中.


获取值栈中的数据

Struts2引入了OGNL表达式,主要是在JSP页面中获取值栈中的值,首先需要先引入Struts2的标签库
<%@ taglib prefix="s" uri="/struts-tags" %>

然后使用Struts2提供的标签中的标签
<s:property value="OGNL表达式"/>

如果要访问对象方法也是可以的,例如:
<s:property value="'hello'.length()"/>

在jsp中 通过<s:debug />可以查看值栈的内容

除此之外,我们也可以使用el表达式来取值。

获取root栈的数据

1.获取push方法保存的数据

package blog.csdn.net.mchenys;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class Demo1Action extends ActionSupport {
	private static final long serialVersionUID = 1L;

	public String demo1() {
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		valueStack.push(new User("mChenys",22));//保存数据到root栈
		return SUCCESS;
	}
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<package name="default" namespace="/" extends="struts-default">
		
		<action name="*" class="blog.youkuaiyun.com.mchenys.Demo1Action" method="{1}">
			<result name="success">/suc.jsp</result>
		</action>
		
	</package>

</struts>

jsp页面取数据

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- 导入struts标签库  -->
<%@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>Insert title here</title>
</head>
<body>
	<!-- 从root栈中取数据
		[0]:从root栈(ArrayList集合)中取数据,数据从0下标开始到最后一个数据位置为止
		[0].top:拿到root栈顶的数据即第一条数据,即User对象
		[0].top.username:通过user对象的username属性获取其值
		注意:[0].top默认可以省略不写
	 -->
	<s:property value="[0].top.username"/>
	
	<!-- 或者直接使用el表达式获取 -->
	${username}
	
</body>
</html>

2.获取set方法保存的数据

package blog.csdn.net.mchenys;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class Demo1Action extends ActionSupport {
	private static final long serialVersionUID = 1L;

	public String demo2() {
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		//保存map集合
		Map<String, User> map = new HashMap<>();
		map.put("one", new User("zhangsan", 20));
		map.put("two", new User("lisi", 22));
		map.put("three", new User("wangw", 23));
		valueStack.set("umap", map); 

		//保存list集合
		List<User> list = new ArrayList<>();
		list.add(new User("tom", 30));
		valueStack.set("ulist", list);

		return SUCCESS;
	}
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- 导入struts标签库  -->
<%@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>Insert title here</title>
</head>
<body>

	<!-- 从root栈中获取map对象中的数据
	
		由于root栈调用set方法,会先将数据添加到一个内部的map集合,然后再将该map集合添加到内部的list集合
		因此:如果外面传入的是map的话,其应该是这样的List<Map<umap,Map<key,value>>>
		
		[0]:从root栈(ArrayList集合)中取数据,数据从0下标开始取,取到最后一个数据位置为止
		[0].top:拿到root栈顶的数据即第一条数据,该条数据是一个内部的map集合,key=umap, value=数据(map对象)
		[0].top.umap:通过key=umap可以拿到数据,而这里的数据又是一个map对象
		
		[0].top.umap.one:通过数据的map的key=one拿到user对象
		[0].top.umap.one.username:通过user对象的username属性获取其值
		注意:[0].top默认可以省略不写
	 -->
	<s:property value="[0].top.umap.one.username"/>
	
	<!-- 或者直接使用el表达式获取 -->
	${umap.one.username}
	
	<!-- 从root栈中取list对象中的数据
		
		[0]:从root栈(List集合)中取数据,数据从0下标开始取,取到最后一个数据位置为止
		[0].top:拿到root栈顶的数据即第一条数据,该条数据是一个内部的map集合,key=ulist, value=数据(list对象)
		[0].top.ulist:通过key=ulist可以拿到数据,数据是一个list对象
		[0].top.ulist[0]:去list集合中第一条数据,即User对象
		[0].top.ulist[0].username:通过user对象的username属性获取其值
		注意:[0].top默认可以省略不写
	-->
	<s:property value="[0].top.ulist[0].username"/>
	
	<!-- 或者直接使用el表达式获取 -->
	${ulist[0].username}
	
</body>
</html>

获取context栈的数据

和context栈存数据一样只能通过特定的对象来获取数据,获取context栈的数据要使用#来标识,一共有以下对象可以获取context域中保存的数据:

request域 :<s:property value="#request.username"/>
session域 : <s:property value="#session.username"/>
application域 : <s:property value="#application.username"/>
attr(最小域开始搜索) : <s:property value="#attr.username"/>
parameters(请求参数) : <s:property value="#parameters.cid"/>

例如:

package blog.csdn.net.mchenys;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class Demo1Action extends ActionSupport {
	private static final long serialVersionUID = 1L;

	public String demo3() {
		HttpServletRequest request = ServletActionContext.getRequest();
		// 存单个对象
		request.setAttribute("user", new User("tom", 30));
		request.getSession().setAttribute("user", new User("jack", 22));

		// 保存list集合
		List<User> list = new ArrayList<>();
		list.add(new User("tom", 30));
		list.add(new User("jack", 22));
		ServletActionContext.getServletContext().setAttribute("ulist", list);

		return SUCCESS;
	}
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- 导入struts标签库  -->
<%@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>Insert title here</title>
</head>
<body>
	<!-- 获取域中的数据 -->
	<s:property value="#request.user.username" />
	<s:property value="#session.user.username" />
	<s:property value="#application.ulist[0].age" />
	
	<!-- 从最小域~最大域中获取数据 -->
	<s:property value="#attr.user.username"/>
	
	<!-- 获取请求参数 例如:http://localhost:8080/Struts2_03/demo3?id=3中的id-->
	<s:property value="#parameters.id" />

</body>
</html>

迭代的标签

通过<s:iterator></s:iterator>标签可以遍历值栈中的集合数据,常用的属性有value和var:
value:要迭代的集合,需要从值栈(root栈或者context栈)中获取
var : (可选参数) 表示迭代过程中遍历出来的对象

注意:
如果写了var,那么会把迭代产生的对象默认压入到context栈中,从context栈取值要加#号;
如果不写var,默认把迭代产生的对象压入到root栈中
无论是压入到哪个栈,取的时候每取出一个就会弹出栈一个.

package blog.csdn.net.mchenys;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class Demo1Action extends ActionSupport {
	private static final long serialVersionUID = 1L;
	
	public String demo4() {
		
		//保存集合到root栈
		ValueStack valueStack = ActionContext.getContext().getValueStack();
		List<User> list = new ArrayList<>();
		list.add(new User("tom", 30));
		list.add(new User("jack", 22));
		valueStack.set("ulist", list);
		
		//保存集合到context栈
		HttpServletRequest request = ServletActionContext.getRequest();
		request.setAttribute("ulist", list);
		
		return SUCCESS;
	}
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- 导入struts标签库  -->
<%@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>Insert title here</title>
</head>
<body>
	<!-- 从root栈中取数据  -->
	<!-- 方式一 ,迭代的数据再次存入root栈中-->
	<s:iterator value="ulist">
		<!-- 从root栈顶取数据,每取一个,弹栈一个-->
		<s:property value="username" />
		<s:property value="age" />
	</s:iterator>
	<!-- 方式二 ,迭代的数据再次存入context栈中-->
	<s:iterator value="ulist" var="u">
		<!-- 从context栈顶取数据,每取一个,弹栈一个-->
		<s:property value="#u.username" />
		<s:property value="#u.age" />
	</s:iterator>
	<hr/>
	<!-- 从context栈中取数据  -->
	<!-- 方式一,迭代的数据再次存入root栈中 -->
	<s:iterator value="#request.ulist">
		<s:property value="username" />
		<s:property value="age" />
	</s:iterator>
	<!-- 方式二,迭代的数据再次存入context栈中 -->
	<s:iterator value="#request.ulist" var="u">
		<s:property value="#u.username" />
		<s:property value="#u.age" />
	</s:iterator>
</body>
</html>

更多的标签,可以查看struts-2.3.24-all\struts-2.3.24\docs\docs\tag-reference.html文档说明


Struts2的2个特殊符号

  1. % 符号的用法
    强制字符串解析成OGNL表达式。
    例如:在request域中存入值,然后在文本框<s:textfield>(Struts2的文本看标签)中取值
    <s:textfield value="%{#request.msg}"/>

    注意: { }中值用’'引起来,此时不再是ognl表达式,而是普通的字符串
    例如:<s:property value="%{'#request.msg'}"/>

  2. $ 符号的用法
    在配置文件中可以使用OGNL表达式,例如:文件下载的配置文件。

<action name="download1" class="blog.youkuaiyun.com.mchenys.DownloadAction">
	<result name="success" type="stream">
		<param name="contentType">${contentType}</param>
		<param name="contentDisposition">attachment;filename=${downFilename}</param>
	</result>
</action>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值