Struts2值栈详解

Struts2值栈详解
基本介绍
     ValueStack是Struts2的一个接口,字面意义为值栈,OgnlValueStack是 ValueStack的实现类,客 户端发起一个请求,struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例, OgnlValueStack贯穿整个Action的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储 到值栈中,并通过OGNL表达式读取值栈中的对象属性值。

PS:这里先说明一个易混淆的问题,那就是 ContextMap和值栈的关系,从广义上来讲, ContextMap中存入了一个值栈的键值对。值栈中又有一个ContextMap的引用,这样就形成了一个互相引用的关系。所以说从广义上来讲,无论是从ContextMap的角度来分析,还是从StackValue的角度来分析,都没问题。有很多文档是以StackValue为起点,逐步分析到ContextMap。不过官方文档,还是以ContextMap作为起点。

值栈的内部结构

OnglValueStack源码


 
 
  1. public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
  2. CompoundRoot root;
  3. transient Map<String, Object> context;
  4. }

CompoundRoot源码

 
 
  1. public class CompoundRoot extends ArrayList {
  2. public CompoundRoot() {
  3. }
  4. public CompoundRoot(List list) {
  5. super(list);
  6. }
  7. public CompoundRoot cutStack(int index) {
  8. return new CompoundRoot(subList(index, size()));
  9. }
  10. public Object peek() {
  11. return get( 0);
  12. }
  13. public Object pop() {
  14. return remove( 0);
  15. }
  16. public void push(Object o) {
  17. add( 0, o);
  18. }
  19. }

由以上源码可以看出,OnglValueStack有两部分,一部分是继承ArrayList实现的一个栈结构,一个就是之前介绍过的,在《ContextMap详解》中介绍过的ContextMap。

关于ContextMap的介绍,这里不再给出,可以参考之前的博客《ContextMap详解》,这里分析下栈结构,也就是CompoundRoot,也就是OGNL三大要素之一的根对象(root),可以参考《ONGL基本使用 》。



CompoundRoot
  • CompoundRoot:存储了action实例,它作为OgnlContext的Root对象。
 
     CompoundRoot继承ArrayList 实现压栈和出栈功能,拥有栈的特点,先进后出,后进先出,最后压进栈的数据在栈顶。
     struts2对原OGNL作出的改进就是Root使用CompoundRoot(自定义栈),使用OnglValueStack
的findValue方法可以在CompoundRoot中从栈顶向栈底查找对象的属性值。
     CompoundRoot作为OgnlContext的Root对象,并且在CompoundRoot中action实例位于栈顶, 当读取achon的属性值时会先从栈顶对象中查找对应的属性,如果找不到则继续查找栈中的其它对象, 如果未找到则到ContextMap中去查找,未找到,则返回null。     

案例

 
 
  1. package com.pc.web.action;
  2. import com.itheima.domain.Student;
  3. import com.opensymphony.xwork2.ActionContext;
  4. import com.opensymphony.xwork2.ActionSupport;
  5. import com.opensymphony.xwork2.util.ValueStack;
  6. /**
  7. * ValueStack存值取值操作
  8. * @author Switch
  9. * 当我们不操作值栈时,默认的栈顶对象是:当前执行的动作类
  10. */
  11. public class ActionTest2 extends ActionSupport {
  12. private String name= "泰斯特";
  13. /**
  14. * @return
  15. */
  16. public String demo2(){
  17. //1.获取ActionContext
  18. //从当前线程上获取
  19. ActionContext context = ActionContext.getContext();
  20. //2.使用ActionContext中的方法获取ValueStack
  21. //context.get(ValueStack.VALUE_STACK)
  22. //context.get("com.opensymphony.xwork2.util.ValueStack.ValueStack");
  23. //
  24. //也可以通过request域获取值栈
  25. //ServletActionContext.getRequest().getAttribute("struts.valueStack");
  26. ValueStack vs = context.getValueStack();
  27. //3.压栈操作:把一个学生对象压入栈顶
  28. Student s = new Student();
  29. s.setName( "switch");
  30. s.setAge( 20);
  31. //压栈操作
  32. vs.push(s);
  33. return SUCCESS;
  34. }
  35. public String getName() {
  36. return name;
  37. }
  38. public void setName(String name) {
  39. this.name = name;
  40. }
  41. }


 
 
  1. <%@page import="com.opensymphony.xwork2.util.ValueStack"%>
  2. <%@page import="com.opensymphony.xwork2.ActionContext"%>
  3. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  4. <%@ taglib uri="/struts-tags" prefix="s" %>
  5. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  6. <html>
  7. <head>
  8. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  9. <title>ValueStack的操作 </title>
  10. </head>
  11. <body>
  12. <%--1、取出ValueStack中第一个name属性的值
  13. 借助s:property标签来获取。
  14. 取值栈中的数据:直接写属性名称,获取的就是属性值。不需要使用#号。
  15. OGNL表达式在获取值栈数据时,默认情况下都是从栈顶逐个对象往下寻找,寻找属性一致的,把属性值取出来。
  16. 只要找到之后,就不再继续寻找。
  17. OGNL表达式获取值栈中的数据,只能是根据属性名称获取属性值。
  18. --%>
  19. Name: <s:property value="name"/> <br/>
  20. Age: <s:property value="age"/>
  21. <hr/>
  22. <%--2、获取指定位置属性值
  23. 使用的 OGNL表达式是:[ x] .name
  24. x指的是值栈中对象的索引位置。
  25. --%>
  26. Name1: <s:property value="[0].name"/> <br/>
  27. Name2: <s:property value="[1].name"/> <br/>
  28. <hr/>
  29. <%--3、当我们使用s:property标签时,没有使用value属性,获取的是栈顶对象。
  30. 当我们不操作值栈时,默认的栈顶对象是:当前执行的动作类
  31. --%>
  32. <s:property/>
  33. <hr/>
  34. <%--4、OGNL表达式在OGNL上下文中查找数据时涉及的方法
  35. 不管是在 Map中找,还是在值栈中找,对应的方法只有一个。
  36. ValueStack的对象中的 findValue( String expr)方法。参数的含义:是一个 OGNL表达式
  37. --%>
  38. <% ActionContext context = ActionContext.getContext();
  39. ValueStack vs = context.getValueStack();
  40. Object o1 = vs.findValue(" name");
  41. out.println(" name is "+ o1);
  42. out.println("< br/>");
  43. Object o2 = vs.findValue("[1].name");
  44. out.println("name1 is "+o2);
  45. out.println(" <br/>");
  46. Object o3 = vs.findValue("#session.sessionMap3");
  47. out.println(o3);
  48. out.println(" <br/>");
  49. Object o4 = vs.findValue("#application.applicationAttr");
  50. out.println(o4);%>
  51. <s:debug> </s:debug>
  52. </body>
  53. </html>

OgnlValueStack中push和set的区别


 
 
  1. public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
  2. CompoundRoot root;
  3. public void push(Object o) {
  4. root.push(o);
  5. }
  6. public void set(String key, Object o) {
  7. //set basically is backed by a Map pushed on the stack with a key being put on the map and the Object being the value
  8. Map setMap = retrieveSetMap();
  9. setMap.put(key, o);
  10. }
  11. private Map retrieveSetMap() {
  12. Map setMap;
  13. Object topObj = peek();
  14. if (shouldUseOldMap(topObj)) {
  15. setMap = (Map) topObj;
  16. } else {
  17. setMap = new HashMap();
  18. setMap.put(MAP_IDENTIFIER_KEY, "");
  19. push(setMap);
  20. }
  21. return setMap;
  22. }
  23. public Object peek() {
  24. return root.peek();
  25. }
  26. private boolean shouldUseOldMap(Object topObj) {
  27. return topObj instanceof Map && ((Map) topObj).get(MAP_IDENTIFIER_KEY) != null;
  28. }
  29. }

PS:通过源码可以看出,push直接将对象压入CompoundRoot中,set如果第一次使用,会创建一个map对象,并将键值对设置进去,如果不是第一次,则会将键值对直接放入该map中。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值