Struts2值栈,从值栈中获取数据,root区set和push方式和context区获取方式

什么是值栈

值栈: ValueStack

当浏览器访问action的时候,会被前端控制器(StrutsPrepareAndExecuteFilter)拦截住,在filter中创建值栈(ValueStack)对象(特点:访问一次,创建一次)

创建完以后,会将访问的整个action对象放在ValueStack中,还会将request,session,servletContext对象的底层用来存储数据的map数据集合放在ValueStack中

还会将当前页面提交的所有数据以map的方式也存放在ValueStack中(ps:存放的都是地址引用)

当整个action执行完毕,action对象会被销毁,ValueStack对象也会被销毁下次访问又是一个新的aciton对象和新的ValueStack对象

也就是说:aciton的生命周期和ValueStack是同步的,ValueStack会伴随action一生

ValueStack: 是struts2提供了一个接口 真正的实现类是:OgnlValueStack

问题: ValueStack是有谁创建的,又是什么时候创建的 ? 
            
             当浏览器访问action的是时候,会被前端控制器给拦截住(StrutsPrepareAndExecuteFilter)
             在前端控制器中,自动创建ValueStack对象(特点: 访问一次action,创建一次ValueStack对象)

             当值栈对象被创建出来之后,会将当前访问的action对象整个放在值栈
             还会将request,session,servletContext的底层用来封装数据的map集合也放在值栈中
             (特点:放的是地址引用)

             当整个action执行完毕后,action会销毁,值栈也跟着销毁
             下一次再访问,又是一个新的action对象和一个新的值栈对象
             所以:值栈的生命周期是伴随action一生的

值栈的内部结构?
         1 获取值栈打断点来看的
         2 通过struts2的内置标签可以将整个值栈结构的数据显示页面:<s:debug></s:debug>

ActionContext与值栈的关系? (为什么就能通过ActionContext获取值栈对象)
         当浏览器访问action的时候,会创建值栈对象,还会创建ActionContext对象
         最后把整个值栈放在actionContext中,然后把整个actionContext与当前线程
         绑定
         
         问题:怎么保证action中获取的actionContext就是自己的 不是别人的?
            将整个actionContext放在当前线程中 进行传递
                    threadLocal(当前线程,actionContext);

 

 值栈的获取方式
ActionContext.getContext.getValueStack()

 

如何操作ValueStack?

       1 往ValueStack的root区域存数据  
                  1 action的属性方式 (掌握) 99%(set方式)
                        action的成员属性数据都会在root区域中
                        因为整个action都在值栈中

Struts2值栈,从值栈中获取数据,root区set和push方式和context区获取方式

package com.it.action;

import java.util.ArrayList;
import java.util.List;

import com.it.bean.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class ActionDemo1 extends ActionSupport{
	// 放在root区域了 因为整个ActionDemo1都在root区域
	   private String username;
	   private List list =new ArrayList();
	   private User user =new User();
	   public String getUsername() {
			return username;
		}
	   public List getList() {
		return list;
	   }
	   

	public User getUser() {
		return user;
	}
	@Override
	   public String execute() throws Exception
	   {
		   // 往值栈的root区域存数据
		   username="zhangsan";
			user.setAge(18);
			user.setUsername("tom");
			list.add(13);
			list.add("ddd");
			
		   // 获取值栈的数据 当前action的username属性(了解)
//		   ValueStack vs = ActionContext.getContext().getValueStack();
//		   Object obj = vs.findValue("username"); // 根据属性 (Property Name)
//		   System.out.println(obj);
//		  
		   return "success";
	   }
}

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>Insert title here</title>
</head>
<body>
		<!-- 通过struts2的内置标签 将整个值栈的内部结构图在页面显示 -->
		<s:debug></s:debug>
		
		<!-- 通过ognl获取值栈的数据 当前action的username属性(掌握)
			 类似调用这个方法:vs.findValue(Property Name);
			 			  		
		 -->
		 <!-- 基本数据类型 -->
		 <s:property value="username"/><br>
		 <hr>
		 <!-- 对象 -->
		<s:property value="user.username"/> 
		<s:property value="user.age"/> 
		<!-- list集合 -->
		<s:property value="list[0]"/> 
		<s:property value="list[1]"/> 
		<hr>
		<!--遍历list集合  -->
		<s:iterator value="list" var="i">
			<s:property value="#i"/> <br>
		</s:iterator>
</body>
</html>

2  ValueStack的API的方式(push方式)
                    push(Object obj) push对象   存对象 (掌握)
                    ValueStack.push();  对象用push  
                             底层:
                                getRoot()  获证整个root区 (不用 理解的)
                                ValueStack.getRoot().push()

Struts2值栈,从值栈中获取数据,root区set和push方式和context区获取方式
java代码

package com.it.action;

import java.util.ArrayList;
import java.util.List;

import com.it.bean.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;

public class ActionDemo2 extends ActionSupport{
	// 往值栈的root区域存数据 值栈的API方式
	@Override
	public String execute() throws Exception {
		User user = new User();
		user.setUsername("jack");
		user.setAge(18);
		String name="tom";
		List list=new ArrayList();
		list.add(123);
		list.add("avd");
//		ValueStack vs = ActionContext.getContext().getValueStack();
//		CompoundRoot root = vs.getRoot();
//		root.push(user);/ //在栈顶  底层:add(0, o);
		ValueStack vs = ActionContext.getContext().getValueStack();
		vs.push(name);
		vs.push(user);
		vs.push(list);//手动压栈顶最后一个保存的在最上面(后进先出)
		return "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>
<!-- 通过struts2的内置标签 将整个值栈的内部结构图在页面显示 -->
<s:debug></s:debug>
<!-- 通过Property Name来获取数据  -->
		<!--获取基本类型数据  -->
		<s:property value="[2].top"/><br>
		<hr>
		<!--获取对象  -->
		<s:property value="username"/><br>
		<s:property value="age"/><br>
		<hr>
		<!-- 获取集合 -->
		<s:property value="[0].top"/><br>
		<hr>
		<!--遍历list  -->
		<s:iterator value="[0].top" var="i">
			<s:property value="#i"/>
		</s:iterator>
</body>
</html>

        
      
      2  往ValueStack的context区域存数据  

package com.it.action;

import java.util.Map;

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

public class ActionDemo3 extends ActionSupport {
@Override
public String execute() throws Exception {
	 // 往值栈的context区域存数据 
	ActionContext context = ActionContext.getContext();
	Map<String, Object> map = context.getSession();
	map.put("msg1", "session....");
	Map<String, Object> map2 = context.getApplication();
	map2.put("msg2", "servletContext...");
	
	// 自定义context区域的key和value
	context.put("msg", "msggggggggggggg"); 
	
   return "success";
}
}

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>Insert title here</title>
</head>
<body>
		<!-- 通过struts2的内置标签 将整个值栈的内部结构图在页面显示 -->
		<s:debug></s:debug>
		
		<!-- 获取xcontext区域的数据  -->
		<s:property value="#session.msg1"/><br/>
		<s:property value="#application.msg2"/><br/>
		<s:property value="#attr.msg1"/>---<s:property value="#attr.msg2"/><br/>
		<s:property value="#msg"/>
		
		<hr/>
		<!-- 值栈的数据也可以用el获取到 -->
		${sessionScope.msg1 }<br/>	
		${applicationScope.msg2 }<br/>
		${requestScope.msg }--->${msg}<br/>
				
		
		
</body>
</html>

 el也可以获取到值栈中的数据

    <!-- el的方式来获取Context数据(了解) -->
            ${sessionScope.sessionmsg} --->${sessionmsg }<br/>
            ${applicationScope.contextmsg} --->${contextmsg }<br/>
            ${requestScope.requestmsg} ---${requestmsg }<br/>
        el ${属性名} 以前依次从 pageContext,request,session,application查找
            

    
    底层:
        之前的el的${msg1} 
            先调用pageContext.getAttribute(..)
                获取到,立即返回
                获取不到,继续调用
                    request.getAttribute(..)  struts2增强了
                        获取到,立即返回
                        获取不到,获取root区找,root区回去context区找
                        
                        如果都没找到 继续调用
                            session.getAttribute(..)
                                获取到,立即返回
                                获取不到,继续调用
                                    application.getAttribute(..)
                                        获取到,立即返回
                                        获取不到,返回""
                                        
    
    在struts的el的底层:装饰者模式
        包装了request.对request.getAttribute方法进行了增强.
            先依次以以前的方式查询
            若都没有查询到,调用了 valueStack.findValue(..)从值栈中查找
                
        以前的: pageContext,request,session,application
            struts包装以后
            最终: pageContext,request,root区,context区,session,application

 

小小的总结三种方式如有错误,欢迎大家指出