Webwork是標(biāo)準(zhǔn)的請(qǐng)求風(fēng)格Web MVC,類似的有Struts、Spring MVC。這這種風(fēng)格的MVC中都使用了前端控制器模式(企業(yè)架構(gòu)模式),也就是說一個(gè)URL會(huì)被解析然后派發(fā)到對(duì)應(yīng)的Action解析,而View調(diào)用的是Action處理后的Form對(duì)象或者Command對(duì)象(Rod的Without EJB)。
上面引用了一些經(jīng)典的言論,而它們和“頁面控制器風(fēng)格Action復(fù)用”有什么關(guān)系呢?
嘿嘿,頁面控制器在這里指到了View的Page里面依然可以調(diào)用控制器(在Webwork中就是Action)。如果是以前肯定有人會(huì)說,如果用JSP我隨時(shí)可以在Page里面寫scriptlet,什么東西都能調(diào)用……
可是,現(xiàn)在不一樣了。我們希望讓View單純一點(diǎn),不要有雜亂無章的邏輯參與其中。
可是,如果要是如上面所說那么Action在它的一個(gè)請(qǐng)求生命周期就要做所有的事……這樣一是使Action邏輯變得復(fù)雜,二是會(huì)變得難以復(fù)用。
所以,說到這里就引出了這個(gè)主題:
1、在頁面調(diào)用控制器
2、復(fù)用控制器邏輯
在Webwork中我們可以使用<ww:action/>標(biāo)簽實(shí)現(xiàn)這個(gè)目的。
——————————————————————————————————————
不要著急,我們先介紹一下ww:action的兩種主要用法,而說用法之前先說語法:
語法:
<ww:action/>有5個(gè)屬性:
1、id:給Action返回的ValueStack命名,如果不寫則默認(rèn)為調(diào)用的Action的名字。(詳細(xì)使用參照后面)
2、name:調(diào)用的Action的name。
3、namespace:調(diào)用的Action的namespace。
4、executeResult:true或false,是否渲染Action的View。這個(gè)決定了ww:action的用法。(后面會(huì)做說明)
5、ignoreContextParams:Boolean值,request參數(shù)是否在Action被調(diào)用時(shí)所包括。
好了,語法很簡(jiǎn)單,我們說ww:action的兩種主要用法。
1、代替<jsp:include>:
include有兩種方式@ include和jsp:include,它們一個(gè)是編譯前一個(gè)是運(yùn)行時(shí)include。webwork是不能使用<jsp:include>的。
但其實(shí)ww有ww:include標(biāo)簽,但是根據(jù)Webwork in Action中的推薦,ww:include標(biāo)簽適合調(diào)用一般servlet,而對(duì)于action則推薦使用強(qiáng)大的ww:action。所以我們這里就略過ww:include。
說強(qiáng)大是什么意思呢?ww:action充當(dāng)這個(gè)角色時(shí),可以選擇是否將valueStack的東西復(fù)制過來。
當(dāng)ww:action代替jsp:include的時(shí)候我們需要executeResult="true",這個(gè)時(shí)候調(diào)用的action返回的view會(huì)被include到調(diào)用的位置。<ww:action><param name="xxx" value="yyy"/></ww:action>則可以給action傳遞參數(shù)。其它的用法就與jsp:include或者ww:include用法差別不大了。
2、頁面控制器風(fēng)格Action復(fù)用:
我們經(jīng)常遇到這樣的場(chǎng)景,比如用戶注冊(cè)的時(shí)候需要選擇單位列表。那么我們r(jià)eg.action運(yùn)行之前就需要先把單位列表unitsList取出來。而它們本身與User注冊(cè)邏輯上沒什么關(guān)系。
所以有的人把這個(gè)取出unitsList單獨(dú)寫在prepare()方法里面,然后用prepare Inteceptor……或者把讀取unitsList的邏輯寫在execute方法里面。
但是這顯然難以復(fù)用!
其實(shí)如果有單位unit這樣的domain,我們可能就有對(duì)應(yīng)的CRUD的Action。其中可能就有UnitsListAction這樣的Action。
我們完全可以在用戶注冊(cè)的時(shí)候就復(fù)用這個(gè)Action,而不是把同樣的邏輯寫到用戶注冊(cè)的Action里面。這就是頁面控制器風(fēng)格要解決的問題。
說那么多大帽子其實(shí)沒有意義,我們看看怎么實(shí)現(xiàn):
UnitsListAction片斷(我們要復(fù)用它):
UnitService unitService = null;//注入,商業(yè)邏輯
List<Unit> unitsList = null;//設(shè)置對(duì)應(yīng)getter、setter
Public String execute() {
unitsList = unitDao.listAll();
return SUCCESS;
}
UserRegAction假設(shè)在注冊(cè)前只是doDefault()直接返回SUCCESS,只有在Post數(shù)據(jù)時(shí)在調(diào)用execute(),我們就不寫空的代碼了。或者不通過任何Action調(diào)用注冊(cè)頁面,直接調(diào)用注冊(cè)的jsp文件直接訪問也可以。
到了UserRegAction顯示的View,我這里是Jsp片斷:
<ww:action id="listUnits" executeResult="false" namespace="/" name="unitsListAction" />
<ww:select name="unitId" list="#attr.listUnits.unitsList" listKey="id" listValue="name" required="true"/>
注意,executeResult="false",也就是說我們不渲染unitsListAction返回的view,只用它的值。
而訪問它的值的時(shí)候要使用#attr.listUnits.unitsList這樣的引用,因?yàn)檫@時(shí)unitsListAction返回的VlueStack不是頁面的ognl的rootStack,我們需要訪問#attr這個(gè)Stack,這部分可以參考一下Webwork的wiki。
上面我給unitsListAction規(guī)定了一個(gè)id,這樣調(diào)用比較靈活,你可以多次調(diào)用同一個(gè)Action并且將值放在#attr下的不同地方。
我們引用unitsListAction返回的unitsList這個(gè)list的時(shí)候需要用#attr加上我們給unitsListAction設(shè)定的id(如果不指定id,則默認(rèn)unitsListAction)再加上你要訪問的變量名訪問。
其實(shí)很簡(jiǎn)單,而這種方式就是開始說的頁面控制器風(fēng)格的action復(fù)用。雖然和真正的葉面控制器的Tapestry和JSF相差甚遠(yuǎn),但是也算有點(diǎn)那個(gè)意思了。
擴(kuò)展點(diǎn)想,如果我們?cè)贏ction實(shí)現(xiàn)了一個(gè)counter,也可以通過這種方式調(diào)用,連返回的值都可以忽略,呵呵,這種邏輯復(fù)用還是挺有用的。
拋磚引玉,我這個(gè)人說話啰嗦,見諒,就到這里。