衆所周知,Strut 2的Action類通過屬性可以獲得所有相關的值,如請求參數、Action
配置參數、向其他Action傳遞屬性值(通過chain結果)等等。要獲得這些參數值,我
們要做的唯一一件事就是在Action類中聲明與參數同名的屬性,在Struts 2調用Action
類的Action方法(默認是execute方法)之前,就會爲相應的Action屬性賦值。
要完成這個功能,有很大程度上,Struts 2要依賴於ValueStack對象。這個對象貫
穿整個Action的生命週期(每個Action類的對象實例會擁有一個ValueStack對象)。當
Struts 2接收到一個.action的請求後,會先建立Action類的對象實例,但並不會調用
Action方法,而是先將Action類的相應屬性放到ValueStack對象的頂層節點
(ValueStack對象相當於一個棧)。只是所有的屬性值都是默認的值,如String類型的
屬性值爲null,int類型的屬性值爲0等。
在處理完上述工作後,Struts 2就會調用攔截器鏈中的攔截器,當調用完所有的攔
截器後,最後會調用Action類的Action方法,在調用Action方法之前,會將ValueStack
對象頂層節點中的屬性值賦給Action類中相應的屬性。大家要注意,在這裏就給我們帶
來了很大的靈活性。也就是說,在Struts 2調用攔截器的過程中,可以改變ValueStack
對象中屬性的值,當改變某個屬性值後,Action類的相應屬性值就會變成在攔截器中最
後改變該屬性的這個值。
從上面的描述很容易知道,在Struts 2的的Action類可以獲得與屬性同名的參數值
就是通過不同的攔截器來處理的,如獲得請求參數的攔截器是params,獲得Action的配
置參數的攔截器是staticParams等。在這些攔截器內部讀取相應的值,並更新
ValueStack對象頂層節點的相應屬性的值。而ValueStack對象就象一個傳送帶,將屬性
值從一個攔截器傳到了另一個攔截器(當然,在這其間,屬性值可能改變),最後會傳
到Action對象,並將ValueStack對象中的屬性的值終值賦給Action類的相應屬性
個人總結:OGNL中的值棧相當於一個數據的中轉站,或者叫數據的緩衝存儲中心。另外,
OGNL除了有值棧(VS)這個特別的對象外,它的表達式語言也自成一派。
值棧和session都是在ActionContext的全局領域內的,按我個人通俗的說法就是
ActionContext最大,並且ActionContext中包含值棧和session這些全局的容器,
因爲actioncontext是線程級的,那麼session就是線程安全的。
下面介紹如何引用值棧中的對象(又稱屬性或者值,什麼叫法不重要,重要的是知道我們是引用值棧內的東西):
我們在jsp頁面是直接面向值棧操作,所以值棧的內容可以直接用名字來引用。值棧外的如session就要用OGNL語法中的#來操作。
對於值棧來說,struts2有專門的tag叫<s:property >來引用值棧內容,如下例:
<s:property
value
=
"artist.bio"
/>
session是值棧外的(全局的,或稱根級別),所以要用OGNL的#符號表達式來引用session裏的對象,如
<s:property
value
=
"#session['artistBio']"
/>
可以先把一個變量級別升高成爲全局,然後用#符號來引用值,那麼用s:set標籤來做,如
<
s:set
name
=
"artistName"
value
=
"artist.name"
/>
=====》級別提高了哦,YEAH!!
<
s:set
name
=
"artistBio"
value
=
"artist.bio"
/>
======》老子級別也高了,YEAH!!
<
b
>Album Title :</
b
> <
s:property
value
=
"title"
/>
<
br
>
<
b
>Artist Name :</
b
> <
s:property
value
=
"#artistName"
/>
<
br
>
<
b
>Artist
Bio :</
b
> <
s:property
value
=
"#artistBio"
/> ===》級別高了,不在值棧內就不能直接引用了。。。。。需要加#號
假如想讓對象不但級別高了(全局的)在整個session週期內持久,就要加上scope,如
<
s:set
name
=
"artistName"
value
=
"artist.name"
scope
=
"session"
/>
<
s:set
name
=
"artistBio"
value
=
"artist.bio"
scope
=
"session"
/>
<
b
>Album Title :</
b
> <
s:property
value
=
"title"
/>
<
br
>
<
b
>Artist Name :</
b
> <
s:property
value
=
"#session['artistName']"
/>
<
br
>
<
b
>Artist Bio :</
b
> <
s:property
value
=
"#session['artistBio']"
/>
<
br
>
下面還有push標籤,用來把對象放到值棧頂端:
<
b
>Album Title :</
b
> <
s:property
value
=
"title"
/>
<
br
>
<
s:push
value
=
"artist"
>
<
b
>Artist Name :</
b
> <
s:property
value
=
"name"
/>
<
br
>
<
b
>Artist Bio :</
b
> <
s:property
value
=
"bio"
/>
<
br
>
</
s:push
>
那麼<s:bean>這個標籤,用來在頁面實例化一個bean放在值棧中,它的生存週期就是到了</s:bean>爲止就結束了,所以說假如要用<s:property>這個標籤來引用該bean的屬性的話,一定要在<s:bean>和</s:bean>標籤之中用。如下面例子:
<
s:bean
name
=
"vaannila.CurrencyConverter"
>
<
s:param
name
=
"dollars"
value
=
"100"
/>
100Dollars =
<
s:property
value
=
"rupees"
/>
Rupees
</
s:bean
>
那麼假如在bean標籤之外引用呢,因爲這時候這個bean的生命週期結束了,已經不在值棧內了,所以要用的話,需要事先在前面bean的聲明地方加上一個變量聲明,使其成爲全局的對象,然後再像引用session變量那樣的方式來引用它,如下例:
<
s:bean
name
=
"vaannila.CurrencyConverter"
var
=
"converter"
>
<
s:param
name
=
"dollars"
value
=
"100"
></
s:param
>
</
s:bean
>
100 Dollars =
<
s:property
value
=
"#converter.rupees"
/>
Rupees