(14)Struts2_值栈

Struts2_值栈

借用在前面演示 hello world 的时候的例子。

在show.jsp 页面那些字段的值到底是怎么取得呢?现在在show.jsp中输出request

<%@ page language="java" import="java.util.*" pageEncoding="utf-8" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  </head>
  <body>
       ID:${id}<br>
       编号:${ dlh}<br>
       姓名:${ name}<br>
       部门:${ bmmc}<br>
      <%=request %>
  </body>
</html>

可见,request是经过Struts包装过后的。

ctrl+shift+t 查看StrutsRequestWrapper类的 源码

public class StrutsRequestWrapper extends HttpServletRequestWrapper {

    private static final String REQUEST_WRAPPER_GET_ATTRIBUTE = "__requestWrapper.getAttribute";
    private final boolean disableRequestAttributeValueStackLookup;

    ......

    /**
     * Gets the object, looking in the value stack if not found
     *
     * @param key The attribute key
     */
    public Object getAttribute(String key) {
        if (key == null) {
            throw new NullPointerException("You must specify a key value");
        }

        if (disableRequestAttributeValueStackLookup || key.startsWith("javax.servlet")) {
            // don't bother with the standard javax.servlet attributes, we can short-circuit this
            // see WW-953 and the forums post linked in that issue for more info
            return super.getAttribute(key);
        }

        ActionContext ctx = ActionContext.getContext();
        Object attribute = super.getAttribute(key);

        if (ctx != null && attribute == null) {
            boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));

            // note: we don't let # come through or else a request for
            // #attr.foo or #request.foo could cause an endless loop
            if (!alreadyIn && !key.contains("#")) {
                try {
                    // If not found, then try the ValueStack
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
                    ValueStack stack = ctx.getValueStack();
                    if (stack != null) {
                        attribute = stack.findValue(key);
                    }
                } finally {
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
                }
            }
        }
        return attribute;
    }
}

当从super.getAttribute(key)获取不到值时,会从ValueStack中去取,super即HttpServletRequestWrapper 。所以,页面输出的值是从值栈里面取到的值,而并非是request请求域中有这么一些属性值。

debug断点调式

ActionContext其实是对OgnlContext的包装。

root即为实际意义上的后进先出的一个栈;值栈在页面取值输出的时候,就是从root属性里取其所含的对象的属性的值。

其中root属性为CompoundRoot对象,查看其源码可知。

public class CompoundRoot extends CopyOnWriteArrayList<Object> {

    private static final long serialVersionUID = 8563229069192473995L;

    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);
    }
}

其继承了list,进栈push添加到第一个,其前的往后移;出栈删除第一个,其后的往前移。


总结:

ValueStack(值栈):

I. 可以从 ActionContext 中获取值栈对象

II. 值栈分为两个逻辑部分

  • Map 栈: 实际上是 OgnlContext 类型, 是个 Map, 也是对 ActionContext 的一个引用. 里边保存着各种 Map: requestMap, sessionMap, applicationMap, parametersMap, attr
  • 对象栈: 实际上是 CompoundRoot 类型, 是一个使用 ArrayList 定义的栈. 里边保存各种和当前 Action 实例相关的对象.是一个数据结构意义的栈.

贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个 ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前 Action 对象和其他相关对象.

Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中


在 ValueStack 对象的内部有两个逻辑部分:

  • ObjectStack: Struts 把 Action 和相关对象压入 ObjectStack 中
  • ContextMap: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中. 实际上就是对 ActionContext 的一个引用

Struts 会把下面这些映射压入 ContextMap 中

  • parameters: 该 Map 中包含当前请求的请求参数
  • request: 该 Map 中包含当前 request 对象中的所有属性
  • session: 该 Map 中包含当前 session 对象中的所有属性
  • application:该 Map 中包含当前 application 对象中的所有属性
  • attr: 该 Map 按如下顺序来检索某个属性: request, session, application

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏desperate633

LeetCode 9. Palindrome Number分析代码

最常规的思路是直接将数反转再对比,但实际上,我们只需要反转后半部分跟前半部分对比就可以了。两种情况,一是位数为偶数,直接对比,位数为奇数,大数除以10对比。

9220
来自专栏小樱的经验随笔

Codeforces 810C Do you want a date?(数学,前缀和)

C. Do you want a date? time limit per test:2 seconds memory limit per test:256 m...

27550
来自专栏小樱的经验随笔

isupper()函数

isupper()函数可以用来判断字符c是否为大写英文字母! 原型:extern int isupper(int c); 头文件:ctype.h 功能:判断字符...

23030
来自专栏Java3y

Struts2【OGNL、ValueStack】

什么是OGNL表达式? OGNL是Object Graphic Navigation Language 是操作对象属性的开源表达式。 Struts2框架使用OG...

35870
来自专栏前端黑板报

Javascript即将迎来Optional Chaining

Optional Chaining 现在处于 Stage 1。 它是什么? Optional Chaining 使我们能检查一个对象上面是否存在某属性。其它一些...

37850
来自专栏蘑菇先生的技术笔记

探索c#之不可变数据类型

21640
来自专栏爱撒谎的男孩

Struts2之OGNL的使用

42950
来自专栏公众号_薛勤的博客

Apache Commons Codec的Base64加解密库

下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi

13340
来自专栏从流域到海域

《笨办法学Python》 第39课手记

《笨办法学Python》 第39课手记 本节课讲列表的操作,用来做练习的代码中出现了之前用到过的几个函数,是一节复习课。你需要记住它们。 原代码如下: ten_...

21870
来自专栏一直在跳坑然后爬坑

RxJava2操作符之“Concat”与“ConcatArray”

emit the emissions from two or more Observables without interleaving them 从两个或更...

39620

扫码关注云+社区

领取腾讯云代金券