Loading

(十一)Struts2进阶之EL和OGNL读取值栈数据对比

上篇文章中说了OGNL在Struts2中的使用方法。然而,EL其实也是可以读取值栈中的数据,那么EL读取值栈的数据和OGNL读取值栈的数据有什么不同呢?



还记得之前那个第八篇文章中的例子吗?代码都和它们一样,只是改一下getvalue.jsp

    <s:iterator value="list" var="user">
        <!-- 每次遍历出来的user对象,都会放到context中去,使用OGNL取root中的数据,
            可以不用#,但取context中的数据,则要加上# 
        -->
        <s:property value="#user.username"/>
        <s:property value="#user.password"/>
    </s:iterator>
    <br>
    使用jstl<br>
    <c:forEach items="${list}" var="user">
        ${user.username}
        ${user.password}
    </c:forEach>

两种方式输出的结果一样。

那么我们就来探讨一下为啥EL也能获取到值栈中的数据?是怎么获取的呢?

带着这个问题,我们来看看Struts2的默认核心控制器,因为它的实质是一个过滤器,过滤所有的页面,所以我们从它下手。

进入它的源码,看它的doFilter方法,里面有这么一句

request = prepare.wrapRequest(request);

这和request有联系,我们进入wrapRequest方法,里面只有这么一句话

request = dispatcher.wrapRequest(request);

那么我们继续进入这个wrapRequest方法,在该方法中,我们有这么一行

request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);

继续进入StrutsRequestWrapper类,终于到达目的地,该类中有这么一个方法

public class StrutsRequestWrapper extends HttpServletRequestWrapper {
    // 获取request中的属性值
    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实例
        ActionContext ctx = ActionContext.getContext();
        // 通过key获取对应的值
        Object attribute = super.getAttribute(key);
        // 如果在request中没有找到对应的值,如果找到了,直接返回
        if (ctx != null && attribute == null) {
            if (!alreadyIn && !key.contains("#")) {
                try {
                    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;
    }
}

通过上面的代码,可以很清楚的看到EL表达式是怎么获取值栈中的值。

总结如下

其实是Struts2底层增强了getAttribute方法
(1)首先从request域获取值,如果找到了,直接返回
(2)如果没有找到,则去值栈中找,然后把值放入域对象中

可以看出使用EL表达式获取值栈中的值效率低,因为它经历了好多步。所以尽量避免使用EL去获取值栈中的值。

posted @ 2018-05-24 20:03  CodeTiger  阅读(29)  评论(0编辑  收藏  举报