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

不知道大家有没有想过这样一个问题:为什么在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;

    }

}
View Code

 

你可能感兴趣的:(struts2)