前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Struts2 之值栈

Struts2 之值栈

作者头像
bgZyy
发布2018-05-16 14:50:26
5770
发布2018-05-16 14:50:26
举报
文章被收录于专栏:Java 技术分享

值栈(ValueStack)

https://cloud.tencent.com/developer/article/1391154 这是我的有关 struts2 的第一篇文章,对于里面我们说到的一个 struts2 HelloWorld 小练习,即在输入框输入信息提交后在另外一个页面显示输入的信息,显示页面的代码如下:

代码语言:javascript
复制
UserName: ${userName}<br>
Email: ${email}<br>
Address: ${address}<br>

  为什么这样一个简单的标签就可以获取到另外一个页面的输入信息,我们使用上面链接中的代码并在其基础上加以改进以得到答案!

  我们知道 struts 默认的请求类型为 dispatcher,即请求转发,那么我们尝试在 show.jsp 中利用 request 域对象打印输入值,如下(在前面加上标识以区分):

代码语言:javascript
复制
UserDesc: ^+^<%= request.getAttribute("userDesc")%><br>

  结果如下图:

  • 我们可以看到利用 request 的 getAttribute() 方法打印的结果和使用标签一样,此时我们应该想到将 request 打印出来,代码以及结果如下: Request: <%= request%>

如上图所示,此时的 request 是已经被 struts2 封装的 request,在 IDEA 中双击 Shift 查找 StrustsRequestWrapper 源代码,找到其 getAttributte() 方法,如下:

代码语言:javascript
复制
public class StrutsRequestWrapper extends HttpServletRequestWrapper {
    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;
    }
}
  • 如上代码所示,我们可以知道 StrutsRequestWrapper 继承自 HttpServletRequestWrapper
  • getAttribute() 方法首先判断传入的 key 是否为空,若是抛出空指针异常
  • 若不是判断传入的 key 值是否满足一定的条件,若满足则直接使用父类的 getAttribute() 方法,获取对应的属性值
  • 若不满足则经过一系列判断后获取到 ValueStack 对象 stack,从 stack 对象中获得对应 key 的属性,并返回

  为了一探究竟我们 Debug 一步步调试查看,首先 Debug 运行程序,在输入页面输入信息之后再在源代码页面上打断点(在源代码页面的 ValueStack 前一行打断点),再点击提交将会跳转到调试页!

  • 第一次运行至断点结果如下图所示,这是 struts2 初始化一些必要的信息
  • 将光标放置在断点行,点击 Run to Cursor(运行至光标处),直到 key 的值为 userName,再点击将依次 userDesc 等,如图
  • 此时点击Step Over 执行代码到下一行,ValueStack 对象将被初始化,如下图所示,在这里我们依次打开 stack,root 在这里我们可以看到一对一对的 key 和 value ,进而我们得知显示页面的值是从此处得来的
  • 一些关于值栈的概念
    • ValueStack(值栈):贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个 ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前 Action 对象和其他相关对象.
    • 在 ValueStack 对象的内部有两个逻辑部分,ObjectStatck 和 ContextMap;
    • struts 把 Action 和相关对象(如上例中的 Info 对象)压入ObjectStack 中,这里所说的 ObjetcMap 即上图中的 root,遵循“先进后出” 的原则
    • ContextMap:Struts 把各种映射关系压入 ContextMap 中,实际上就是一些对 ActionContext 的引用(parameters、request、session、application、attr)

  至此我们得知显示页面的底层实现,即从 ValueStack 中获取,其默认从栈顶开始寻找与 key 值匹配的属性,依次往下,也了解到值栈的基本概念,接下来让我们着手利用 OGNL 获取值栈里对象的属性。

OGNL

  • 在 JSP 页面上利用 OGNL 访问值栈里对象的属性,若希望访问值栈中 ContextMap 中的数据,需要给 OGNL 表达式前面加上一个前缀 #,如果没有添加将会在 ObjectStack 中进行,如下示例在 session 内找 key 为 sessionMap 的属性 <s:property value="#session.sessionMap"/>
  • property 标签
    • Struts2 的 property 标签用来输出值栈中的一个属性值
    • 其属性 value 表示来自栈顶对象在页面上将要显示的值(String 类型)
    • 其属性 default 表示若 value 若为空,将显示该值(String 类型)
    • 其属性escape 表示是否对 HTML 特殊字符进行转义
  • 读取规则
    • 读取 ObjectStack 里的对象的属性,ObjectStack 里的对象可以通过一个从零开始的下标来引用,即可以使用0.userName 来返回栈顶对象的 message 属性,结合
    • 若在指定的对象中没有找到指定的属性,则到指定对象的下一个对象里继续搜索,即 n 的意义是从第 n 个开始搜索,而不是只搜索第 n 个
    • 若从栈顶对象开始搜索则可以省略下标
    • 默认情况下 Action 对象会被 Struts2 自动的放到值栈的栈顶 // 如下两种写法都是从栈顶开始在对象栈中查找 key 为 userName 的属性
    • <s:property value="userName"/>
    • <s:property value="0.userName"/>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-04-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 值栈(ValueStack)
  • OGNL
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档