ValueStack(值栈): 贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个ValueStack对象,每次请求都会创建一个Action类)。请求完成后ValueStack与request将一起消失。
ValueStack相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象.
ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础
Struts框架把ValueStack对象保存在名为“struts.valueStack” 的请求属性中,request中ServletActionContext类中提供了一个常量
public static final String STRUTS_VALUESTACK_KEY = “struts.valueStack”;
值栈的获取:
//获取方式一
ValueStack valueStack = ActionContext.getContext().getValueStack();
//获取方式二
ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
在 ValueStack 对象的内部有两个逻辑部分:
ObjectStack: Struts把动作和相关对象压入ObjectStack中,底层实现对象为CompoundRoot, CompoundRoot是一个ArrayList
ContextMap: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中。底层为Map
对值栈的操作,默认都是Root对象的操作,访问数据时不需要使用#号
Struts 会把下面这些映射压入 ContextMap 中,获取时间是需要使用#号
parameters: 该 Map 中包含当前请求的请求参数
request: 该 Map 中包含当前 request 对象中的所有属性
session: 该 Map 中包含当前 session 对象中的所有属性
application:该 Map 中包含当前 application 对象中的所有属性
attr: 该 Map 按如下顺序来检索某个属性: request, session, application
ValueStack内部底层图解分析:
OgnlValueStack 类包含两个重要的属性:一个root和一个context。
其中root本质上是一个ArrayList.
而context 是一个Map(更确切的说是一个OgnlContext对象)
在这个OgnlContext对象(context)中,有一个默认的顶层对象_root,OGNL访问context中这个默认顶层对象中的元素时,是不需要#号的,直接通过元素的名称来进行访问,而访问其他对象时,如 request、session、attr等,则需要#号引用。
Struts2将OgnlValueStack的root对象赋值给了OgnlContext中的_root对象,在OgnlValueStack的root对象中,保存着调用Action的实例,因此,在页面上通过Struts2标签访问Action 的属性时,就不需要通过#号来引用
总结:ognl Context包含 ObjectStack属性和ContextMap属性
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。
ServletActionContext.getRequest()
.setAttribute("username", "username_request");
ServletActionContext.getContext().getSession()
.put("username", "username_session");
ServletActionContext.getServletContext()
.setAttribute("username", "username_application");
ActionContext提供了对ognl上下文对象中数据操作的方法.
valueStack = ServletActionContext.getContext().getValueStack();
valueStack.set("username", "username_valueStack");
valueStack.push(new User("u001", "zhangsan", "12345"));
值栈的使用示例:
action类:
package com.my.action;
import com.my.bean.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.util.ValueStack;
public class ValueStackAction extends ActionSupport implements ModelDriven<User> {
private User user = new User();
@Override
public String execute() throws Exception {
//获得值栈
ValueStack valueStack = ActionContext.getContext().getValueStack();
// 给context 存放数据
ActionContext.getContext().put("ac", "request_ValueStack"); //给Map栈中存放数据
ActionContext.getContext().getSession().put("ac", "session_ValueStack"); //将数据存放在context Map中 key为session ,value = entry(key = value)
ActionContext.getContext().getApplication().put("ac", "application_ValueStack");
// 将栈顶的数据弹出
// valueStack.pop();
User user = new User(); //查询结果
user.setUsername("zhangsan");
user.setPassword("1234");
this.user = user;
return SUCCESS;
}
@Override
public User getModel() {
return this.user ;
}
}
action配置:
<action name="valueStackAction" class="com.my.action.ValueStackAction">
<result name="success">/success.jsp</result>
</action>
valueStack.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
<form action="${pageContext.request.contextPath}/valueStackAction" method="post">
用户名:<input type="text" name="username" /> <br/>
密码:<input type="text" name="password" /> <br/>
<input type="submit" value="提交" />
</form>
</body>
</html>
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!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>
<br/>
<s:debug></s:debug>
<!-- 从context获得数据 -->
<s:property value="#ac"/> <br/>
<s:property value="#session.ac"/> <br/>
<s:property value="#application.ac"/> <br/>
<hr/>
<!-- 使用el获取内容 -->
${requestScope.ac} <br/> <!-- struts 对request的getAttribute方法进行增强,先从request获取内容,再从值栈从获取内容 -->
<% request.getAttribute("ac"); %> <br/>
<%=request %> <br/>
<!-- -->
<s:property value="ac"/> <br/> <!-- 先从root栈中获取内容,再从map栈获取内容 -->
###<s:property value="#request.ac"/> <br/>
<hr/>
<!-- 可以显示表单提交的数据 -->
<s:property value="username"/> <br/>
<s:property value="password"/> <br/>
<!-- Action中执行了valueStack.pop(); -->
<s:property value="model.username"/> <br/>
<s:property value="model.password"/> <br/>
</body>
</html>
运行结果:
struts2提供了一个<s:debug></s:debug>标签可以对值栈进行详细的显示。
运行结果:
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/12071.html