struts2 request内幕 为什么在struts2用EL表达式可以取值

来源:互联网 发布:网络语石锤是什么意思 编辑:程序博客网 时间:2024/06/05 03:27

不知道大家有没有想过这样一个问题: 为什么在action中的实例变量,没有使用request.setAttribute()方法将值添加到request范围内,却能在jsp中用EL表达式取出?

众所周知,EL表达式只能取出pageContext,request,session,application属性范围的值。然而,在struts2中能突破这一个限制,成功的取出action中的实例变量值。

请看例子:

这是一个action

package com.wuyou.action;import com.opensymphony.xwork2.ActionSupport;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Controller;@Controller@Scope(value = "prototype")public class TestAction extends ActionSupport {    private Integer id = 123;    private String name = "无忧之路";    public String execute() {        return "success";    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

对应的struts配置文件:

<package name="default" extends="struts-default" namespace="/">        <action name="test" class="testAction">            <result>/success.jsp</result>        </action>    </package>

对应的success.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title></title></head><body>${id}</body></html>

页面输出:123

其实,在struts2中使用的request并非为tomcat提供的,而是经过了struts2所包装过的org.apache.struts2.dispatcher.StrutsRequestWrapper对象。

这个类做了些什么事情呢?

原来,我们在调用EL表达式的时候,或者request.getAttribute(String key)方法的时候,struts2会先在原来的request中调用request.getAttribute()方法获取该值,如果查找不到,则继续往OgnlValueStack查找,由于action对象在ognl值栈,返回action里名为"id"的实例变量值,即可显示在页面上。

我们可以尝试在jsp中输出request的类名:

<%=request.getClass()%>

也可以在action里面输出:

System.out.println(ServletActionContext.getRequest().getClass());

均输出:class org.apache.struts2.dispatcher.StrutsRequestWrapper

这下真相大白了吧!

附StrutsRequestWrapper类源代码:

public class StrutsRequestWrapper extends HttpServletRequestWrapper {    /**     * The constructor     * @param req The request     */    public StrutsRequestWrapper(HttpServletRequest req) {        super(req);    }    /**     * Gets the object, looking in the value stack if not found     *     * @param s The attribute key     */    public Object getAttribute(String s) {        if (s != null && s.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(s);        }        ActionContext ctx = ActionContext.getContext();        Object attribute = super.getAttribute(s);        if (ctx != null) {            if (attribute == null) {                boolean alreadyIn = false;                Boolean b = (Boolean) ctx.get("__requestWrapper.getAttribute");                if (b != null) {                    alreadyIn = b.booleanValue();                }                    // note: we don't let # come through or else a request for                // #attr.foo or #request.foo could cause an endless loop                if (!alreadyIn && s.indexOf("#") == -1) {                    try {                        // If not found, then try the ValueStack                        ctx.put("__requestWrapper.getAttribute", Boolean.TRUE);                        ValueStack stack = ctx.getValueStack();                        if (stack != null) {                            attribute = stack.findValue(s);                        }                    } finally {                        ctx.put("__requestWrapper.getAttribute", Boolean.FALSE);                    }                }            }        }        return attribute;    }}