【Struts】值栈详解
来源:互联网 发布:中文域名网站 编辑:程序博客网 时间:2024/06/15 09:07
基本介绍
ValueStack是Struts2的一个接口,字面意义为值栈,OgnlValueStack是 ValueStack的实现类,客 户端发起一个请求,struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例, OgnlValueStack贯穿整个Action的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储 到值栈中,并通过OGNL表达式读取值栈中的对象属性值。
PS:这里先说明一个易混淆的问题,那就是ContextMap和值栈的关系,从广义上来讲,ContextMap中存入了一个值栈的键值对。值栈中又有一个ContextMap的引用,这样就形成了一个互相引用的关系。所以说从广义上来讲,无论是从ContextMap的角度来分析,还是从StackValue的角度来分析,都没问题。有很多文档是以StackValue为起点,逐步分析到ContextMap。不过官方文档,还是以ContextMap作为起点。
值栈的内部结构
OnglValueStack源码
- public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
- CompoundRoot root;
- transient Map<String, Object> context;
- }
CompoundRoot源码
- public class CompoundRoot extends ArrayList {
- public CompoundRoot() {
- }
- public CompoundRoot(List list) {
- super(list);
- }
- public CompoundRoot cutStack(int index) {
- return new CompoundRoot(subList(index, size()));
- }
- public Object peek() {
- return get(0);
- }
- public Object pop() {
- return remove(0);
- }
- public void push(Object o) {
- add(0, o);
- }
- }
由以上源码可以看出,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。
案例
- package com.pc.web.action;
-
- import com.itheima.domain.Student;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionSupport;
- import com.opensymphony.xwork2.util.ValueStack;
-
-
-
-
-
-
- public class ActionTest2 extends ActionSupport {
-
- private String name="泰斯特";
-
-
-
- public String demo2(){
-
-
- ActionContext context = ActionContext.getContext();
-
-
-
-
-
-
- ValueStack vs = context.getValueStack();
-
- Student s = new Student();
- s.setName("switch");
- s.setAge(20);
-
- vs.push(s);
-
- return SUCCESS;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
- }
- <%@page import="com.opensymphony.xwork2.util.ValueStack"%>
- <%@page import="com.opensymphony.xwork2.ActionContext"%>
- <%@ 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>ValueStack的操作</title>
- </head>
- <body>
- <%--1、取出ValueStack中第一个name属性的值
- 借助s:property标签来获取。
- 取值栈中的数据:直接写属性名称,获取的就是属性值。不需要使用#号。
- OGNL表达式在获取值栈数据时,默认情况下都是从栈顶逐个对象往下寻找,寻找属性一致的,把属性值取出来。
- 只要找到之后,就不再继续寻找。
-
- OGNL表达式获取值栈中的数据,只能是根据属性名称获取属性值。
- --%>
- Name:<s:property value="name"/><br/>
- Age:<s:property value="age"/>
- <hr/>
- <%--2、获取指定位置属性值
- 使用的OGNL表达式是:[x].name
- x指的是值栈中对象的索引位置。
- --%>
- Name1:<s:property value="[0].name"/><br/>
- Name2:<s:property value="[1].name"/><br/>
- <hr/>
- <%--3、当我们使用s:property标签时,没有使用value属性,获取的是栈顶对象。
- 当我们不操作值栈时,默认的栈顶对象是:当前执行的动作类
- --%>
- <s:property/>
- <hr/>
- <%--4、OGNL表达式在OGNL上下文中查找数据时涉及的方法
- 不管是在Map中找,还是在值栈中找,对应的方法只有一个。
- ValueStack的对象中的findValue(String expr)方法。参数的含义:是一个OGNL表达式
- --%>
- <% ActionContext context = ActionContext.getContext();
- ValueStack vs = context.getValueStack();
- Object o1 = vs.findValue("name");
- out.println("name is "+o1);
- out.println("<br/>");
- Object o2 = vs.findValue("[1].name");
- out.println("name1 is "+o2);
- out.println("<br/>");
- Object o3 = vs.findValue("#session.sessionMap3");
- out.println(o3);
- out.println("<br/>");
- Object o4 = vs.findValue("#application.applicationAttr");
- out.println(o4);%>
- <s:debug></s:debug>
- </body>
- </html>
OgnlValueStack中push和set的区别
- public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
- CompoundRoot root;
- public void push(Object o) {
- root.push(o);
- }
-
- public void set(String key, Object o) {
-
- Map setMap = retrieveSetMap();
- setMap.put(key, o);
- }
-
- private Map retrieveSetMap() {
- Map setMap;
- Object topObj = peek();
- if (shouldUseOldMap(topObj)) {
- setMap = (Map) topObj;
- } else {
- setMap = new HashMap();
- setMap.put(MAP_IDENTIFIER_KEY, "");
- push(setMap);
- }
- return setMap;
- }
-
- public Object peek() {
- return root.peek();
- }
-
- private boolean shouldUseOldMap(Object topObj) {
- return topObj instanceof Map && ((Map) topObj).get(MAP_IDENTIFIER_KEY) != null;
- }
- }
PS:通过源码可以看出,push直接将对象压入CompoundRoot中,set如果第一次使用,会创建一个map对象,并将键值对设置进去,如果不是第一次,则会将键值对直接放入该map中。