1. 程式人生 > >day33Struts2Day03(OGNL表示式、值棧)

day33Struts2Day03(OGNL表示式、值棧)

回顧
1、Servlet的API
    ActionContext物件
    ServletActionContext物件
2、結構型別的跳轉
    全域性結果
    區域性結構 type屬性
3、資料的封裝
    屬性驅動方式
    模型驅動方式 實現ModelDrivern 介面
4、攔截器(自定義攔截器)

OGNL表示式概述
1、OGNL是Object Navigation Language(物件圖導航語言)
    所謂物件圖,即以任意一個物件為根,通過OGNL可以訪問與這個物件關聯的其他物件 
    通過它簡單一致的表示式語法,可以存取物件的任意屬性,呼叫物件的方法,遍歷整個物件的結構圖,實現欄位型別轉換等功能。使用相同的表示式去存取物件的屬性

2、Struts2框架使用OGNL作為預設的表示式語言
    OGNL是一種比EL強大很多倍的語言
    xwork提供OGNL表示式
    ognl-3.0.5.jar

3、OGNL提供五大類功能
    支援物件方法呼叫
    支援類靜態的方法呼叫和值訪問
    訪問OGNL上下文(OGNL context)和ActionContext
    支援賦值操作和表示式串聯
    操作集合物件

1、什麼是值棧
    值棧就相當於Struts2框架的資料的中轉站,向值棧存入一些資料,從值棧中獲取到資料
    ValueStack 是Struts2提供一個介面,實現類OgnlValueStack--值棧物件(OGNL是從值棧中獲取資料的)
    Action是多例的,有一起請求,建立Action例項,建立一個ActionContext物件,代表的是Action的上下文物件,還會建立一個ValueStack物件
    每個Action例項都有一個ValueStack物件(一個請求,對應一個ValueStack物件)
    在其中儲存當前Action物件和其他相關物件
    Struts框架把ValueStack物件儲存在名為“struts.valueStack”的請求屬性中,request中(值棧物件是request一個屬性)
        ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");

2、值棧的內部結構
    值棧由兩部分組成
        root        Struts把動作和相關物件壓入ObjectStack中--List
        context     Struts把各種各樣的對映關係(一些Map型別的物件)壓入ContextMap中

    Struts會預設把下面這些對映壓入ContextMap(Context)中
        request代表的是Map集合的key值,value值其實也是一個Map值
        parameters:該Map中包含當前請求的請求引數?name=xxx&password=123
        request:該Map中包含當前request物件中的所有屬性
        session:該Map中包含當前session物件中的所有屬性
        application:該Map中包含當前application物件中的所有屬性
        attr:該Map按如下順序來檢索某個屬性:request、session、application

    ValueStack存在root屬性(CompoundRoot)context屬性(OgnlContext)、
        CompoundText就是ArrayList
        OgnlContext就是Map

    context對應Map引入root物件
        context中還存在request、session、application、attr、parameters物件引用

        OGNL表示式訪問值棧中的資料
            訪問root中資料時,不需要#
            訪問request、session、application、attr、parameters物件資料必須寫#
        操作值棧預設指操作root元素

3、值棧物件的建立,ValueStack和ActionContext是什麼關係
    值棧物件是請求時建立的
    ActionContext是繫結到當前的執行緒上,那麼在每個攔截器或者Action中獲取的ActionContext是同一個
    ActionContext中存在一個Map集合,該Map集合和ValueStack的contextMap是同一個地址
    ActionContext中可以獲取到ValueStack的引用

4、獲取值棧物件
    (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
    (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

    ActionContext.getContext().getValueStack();

5、向值棧儲存資料(主要針對root棧)
    valueStack.push(Object obj)
        push方法的底層呼叫root物件的push方法(把元素新增到0位置)

    valueStack.set(String key,Object obj)
        原始碼獲取map集合(map可能是已經存在的,有可能是新建立的)把map集合push到棧頂,再把資料存入到map集合中

    在jsp中通過<s:debug/>檢視值棧的內容

6、從值棧中獲取值
    訪問root中資料 不需要#
    訪問context其他物件資料 加#
    如果向root中存入物件的話 優先使用push方法
    如果向root中存入集合的話,優先要使用set方法

    在OGNLContext中獲取資料
        在Action中向與物件中存入值
        xxxx:<s:property value="#xxxx.屬性"/>
        request、session、application、attr、parameters

7、獲取到值棧中的資料
    為什麼EL也能訪問值棧中的資料
        StrutsPreparedAndExecuteFilter的doFilter程式碼中 request = prepare.wrapRequest(request)
        對request物件進行了保證,StrutsRequestWrapper
    org.apache.struts2.dispatcher.StrutsRequestWrapper  
        增強了request的getAttribute
             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);
                }
            }
        訪問request範圍的資料時,如果資料找不到,在值棧中找
        request物件 具備訪問值棧資料的能力(查詢root的資料)

OGNL的特殊符號
1、#符號的用法
    獲取contextMap中的資料
        <s:property value="#xxxx.屬性"/>
        request/session/application/attr/parameters
    構建一個集合
        性別<s:radio name="sex" list="{'男','女'}"></s:radio> 
        性別<s:radio name="sex" list="#{'1':'男','2':'女'}"></s:radio>

2、%符號的用法
    強制字串解析成OGNL表示式
        例如:在request域中存入值,然後在文字框(<s:textfield>)中取值,現在到value上
        <s:textfield value="%{#request.msg}"/>
    {}中值用''引起來,此時不再是ognl表示式,而是普通的字串
        <s:property value="%{'#request.msg'}"/>
        <s:property value="'aaa'"/> 
3、$符號的用法
    在配置檔案中可以使用OGNL表示式,例如:檔案下載的配置檔案
    <action name="download" class="my.demo2.DownLoadAction">
            <result>
                <param name="contentType">${contentType}</param>
                <param name="contentDisposition">attachment:filename=${downFilename}</param>
            </result>
        </action>