傳智播客-struts2(4)-OGNL

struts2裏的OGNL很好很強大!最最有力的證據就是:張老師花了strtuts2總課程一半以上的時間來講解滴~~~

 

OGNL
OGNL是Object Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。Struts2框架使用OGNL作爲默認的表達式語言。

 

相對EL表達式,它提供了平時我們需要的一些功能,如支持對象方法調用,如xxx.sayHello();支持類靜態方法調用和值訪問,表達式的格式爲@[類全名(包括包路徑)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@cn.itcast.Constant@APP_NAME;操作集合對象等。

 

ActionContext與OGNLContext
OGNL有一個上下文(Context)概念,說白了就是一個map結構,它實現了java.utils.Map接口,在struts2中OGNL Context的實現爲ActionContext(官方文檔語:The framework sets the OGNL context to be our ActionContext)。不過OGNLContext與ActionContext並不一致,這是兩個不同的類,且分屬不同的jar包。例如,ActionContext.getContext().getContextMap()得到的是OGNLContext實例;ActionContext.getContext()得到的是ActionContext實例。

 

OGNL Context結構示意圖如下:
                             |--request(map對象)
                             |--application(map對象)
OGNL Context -----|--OgnlValueStack root變量[action, OgnlUtil, ... ]  
                             |--session(map對象) 
                             |--attr(map對象)  
                             |--parameters(map對象)

 

從ActionContext源碼可以看出,上述六個實例都被“set”到了ActionContext裏,所以說“在struts2中OGNL Context的實現爲ActionContext”。而且ActionContext.getContext().getContextMap().get("session")==ActionContext.getContext().getSession(),但是奇怪的是,application、session、attr以及parameters對象的獲取方式ActionContext都提供了getXXX()方法,唯獨沒有getRequest()方法。不知道是開發者遺漏了還是出於其他的考慮。。。

 

OGNLContext與ValueStack
Struts2中設置的OGNL Context的根對象爲ValueStack(OGNLValueStack爲其唯一的實現類),所以Struts2中應用的OGNL Context也被稱之爲ValueStack Context。

 

1、訪問OGNL與ValueStack裏的對象
(1)可以用#key的形式訪問OGNL Context對象中的各個key對應的對象,並可以採用點(.)操作符進行多級導航調用對象的屬性和方法,例如,#application、#session.attr1、#key1.sayHello()。
(2)如果要訪問根對象的屬性或方法,則可以省略#key,直接訪問該對象的屬性和方法, struts2修改了OGNL表達式的默認屬性訪問器,它不是直接訪問根對象ValueStack的屬性或方法,而是在ValueStack內部的堆棧中所有對象上逐一查找該屬性或方法,搜索順序是從棧頂對象開始尋找,依次往下,直到找到爲止,例如,sayHello()表示調用堆棧中某個對象的sayHello()方法。
(3)特例:如果引用名前面沒有#,且valueStack中存儲的各個對象沒有該屬性,則把該名稱當作Context對象中的某個key來檢索對應的對象,但這種方式不支持點(.)操作符。

 

2、ValueStack提供瞭如下一些方法管理其內部的堆棧和關聯的Context:
(1)setValue爲ognl表達式尋址到的對象設置屬性值。
(2)findValue方法使用OGNL表達式獲取結果。
(3)findString方法對findValue方法獲取的結果調用轉換器轉成字符串,如果該對象的類型沒有相關轉換器,則調用toString方法,並返回結果字符串。一個特殊之處:如果不用#前綴訪問ValueStack Context中的對象,則該對象必須是String類型。

 

需要注意的是,Struts2中OGNL表達式需要配合Struts標籤纔可以使用,例如<s:property value="name"/>。

 

ModelDriven
如果action實現了ModelDriven接口,getModel()方法得到的對象將會被直接壓入OGNLValueStack的棧頂。但是該action必須先將model實例化,否則會報空指針異常。下面是ModelDrivenInterceptor的部分源碼:
@Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();

        if (action instanceof ModelDriven) {
            ModelDriven modelDriven = (ModelDriven) action;
            ValueStack stack = invocation.getStack();
            Object model = modelDriven.getModel();
            if (model !=  null) { //從下文可以看到,沒有對model == null的情況進行處理
             stack.push(model); //如果model不爲null,則壓入ValueStack棧頂
            }
            if (refreshModelBeforeResult) {
                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
            }
        }
        return invocation.invoke();
    }

 

如果沒有使用ModelDriven方式,struts2會先調用action的get方法,如果得到的對象爲空,則幫助實例化該對象,然後再調用action裏相應的set方法將該對象壓入到ValueStack。

 

ModelDriven主要是struts2爲了兼容struts1而設計的一個解決方案,如果開發全新的struts2項目,不推薦使用該方式(官方文檔語)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章