您好,登錄后才能下訂單哦!
要讀懂這節(jié)內(nèi)容,并學(xué)會(huì)使用狀態(tài)模式開(kāi)發(fā)Portlet,你必須具備這里提到的幾種設(shè)計(jì)思路,并具備基本的Java開(kāi)發(fā)技能。這里我們選用的開(kāi)發(fā)工具是 IBM Rational Application Developer以及Portlet Toolkit,你需要熟悉該工具,并懂得如何創(chuàng)建Portlet和Portlet所需的包、類(lèi)、頁(yè)面,以及運(yùn)行環(huán)境所需的.jar。
StateManagerPortlet是主要的Portlet類(lèi),并且是Portlet無(wú)關(guān)的。它用作分派器以支持駐留著Portlet代碼的操作和狀態(tài)類(lèi),特定于Portlet的控制器代碼就存在于該類(lèi)中。擴(kuò)展Action抽象類(lèi)的類(lèi)實(shí)現(xiàn)了actionPerformed方法,該類(lèi)執(zhí)行實(shí)現(xiàn)特定的操作請(qǐng)求行為所必需的任何控制器功能。
實(shí)現(xiàn)狀態(tài)接口的類(lèi)將實(shí)現(xiàn)一個(gè)performView方法,該方法是由 StateManagerPortlet 的 service 方法調(diào)用的。該方法還包含通常駐留在這些方法中的代碼。同樣,這段代碼也是特定于它所駐留的狀態(tài)類(lèi)的,因此就避免了確定請(qǐng)求的操作帶來(lái)的所有額外的控制邏輯混亂。
應(yīng)用狀態(tài)模式會(huì)使實(shí)現(xiàn)變得簡(jiǎn)潔。而且,當(dāng)在Portlet的各種模式之間切換時(shí),狀態(tài)總是被記住的。有了這種模式,你就可以輕松地確定想要何時(shí)以及在何處從源檢索數(shù)據(jù),還可以確定何時(shí)應(yīng)該從高速緩存檢索數(shù)據(jù)。由于在門(mén)戶(hù)頁(yè)面刷新時(shí)不調(diào)用actionPerformed方法,所以可以將數(shù)據(jù)訪問(wèn)代碼放在操作狀態(tài)中并在那里高速緩存它們。狀態(tài)類(lèi)可以使用高速緩存中的數(shù)據(jù),以避免刷新門(mén)戶(hù)頁(yè)面時(shí)多次存取數(shù)據(jù)。
考慮到簡(jiǎn)單的基于 MVC 的 Portlet,它從遠(yuǎn)程機(jī)器上將包含一個(gè)產(chǎn)品下載配置參數(shù)列表的XML文件拷貝到本地(Portal系統(tǒng)所在的主機(jī)),檢索各項(xiàng)參數(shù),并把列表呈現(xiàn)給用戶(hù)。在用戶(hù)選擇了某一項(xiàng)后將顯示詳細(xì)的視圖,該視圖顯示的是被選擇項(xiàng)的詳細(xì)信息。這個(gè)詳細(xì)視圖可能涉及向數(shù)據(jù)庫(kù)再次發(fā)出請(qǐng)求。有編輯權(quán)限的用戶(hù)可以進(jìn)入到Portlet的編輯模式,查看并修改XML文件的內(nèi)容,保存后如果發(fā)現(xiàn)XML文件已經(jīng)做了修改,則傳回遠(yuǎn)程機(jī)器;否則,仍將文件包存在Portal本地,以免占用系統(tǒng)資源。
第一步,控制器必須調(diào)用業(yè)務(wù)對(duì)象來(lái)創(chuàng)建合適的Bean,該Bean被傳遞給JSP以用于主視圖中的顯示。第二步,控制器在用戶(hù)的請(qǐng)求中檢索被選擇項(xiàng)的指示器,然后調(diào)用業(yè)務(wù)對(duì)象來(lái)創(chuàng)建合適的Bean,該Bean被傳遞給不同的 JSP以用于詳細(xì)視圖中的顯示。
在 MVC實(shí)現(xiàn)中,視圖組件顯然是不同的。這兩種視圖需要有兩種不同的JSP。你可能需要訪問(wèn)不同的業(yè)務(wù)模型組件來(lái)生成每個(gè)請(qǐng)求所需的Bean??刂破骱瘮?shù)需要知道:
— 調(diào)用哪些業(yè)務(wù)方法?
— 生成哪些Bean?
— 把這些請(qǐng)求對(duì)象上的Bean放在哪里?
— 如何調(diào)用合適的JSP?
這就是代碼變得復(fù)雜的地方。如果使用Servlet編程,那么可能選擇把它們實(shí)現(xiàn)為不同的Servlet,以使每個(gè)合適的Servlet 類(lèi)的服務(wù)方法自然地分隔每個(gè)請(qǐng)求的控制器函數(shù)。如果你更喜歡使用分派器方式而不是不同的Servlet實(shí)現(xiàn),那么必須使用框架(例如Struts)來(lái)實(shí)現(xiàn)類(lèi)似的MVC設(shè)計(jì)。
這是復(fù)雜的任務(wù),因?yàn)椴荒苓x擇使用多個(gè)Portlet 類(lèi)來(lái)實(shí)現(xiàn)一個(gè) Portlet,不能直接處理 Portlet類(lèi)。相同的Portlet的服務(wù)方法用來(lái)處理返回給該Portlet的所有HTTP請(qǐng)求,因此,需要實(shí)現(xiàn)控制代碼類(lèi)具有如下功能。
— 確定正在請(qǐng)求哪個(gè)操作?
— 需要進(jìn)行哪些處理?
— 使Portlet 處于哪種狀態(tài)?
— 顯示什么內(nèi)容返回給用戶(hù)?
我們?cè)?/span>Linux主機(jī) test.cn.ibm.com上運(yùn)行著一個(gè)自動(dòng)下載的程序,要下載的產(chǎn)品列表及各產(chǎn)品的參數(shù)保存在 /home/isc/downLoadConfig/下,文件名為AutodownConfig.xml。我們?cè)?/span>Windows 2000 Server 主機(jī)Netecauto01上運(yùn)行著IBM WebSphere Portal 5.1,普通用戶(hù)只能查看產(chǎn)品列表及配置權(quán)限,當(dāng)該用戶(hù)要查看配置信息時(shí),Portlet 能從服務(wù)器上將文件AutodownConfig.xml拷貝到本地服務(wù)器,并讀出XML文件中的內(nèi)容,顯示在列表中。具有管理權(quán)限的用戶(hù)還有修改各配置信息的權(quán)限,能對(duì)產(chǎn)品配置信息的各項(xiàng)參數(shù)進(jìn)行修改。修改完成后,要使該配置有效,必須將該XML文件回傳到pvcent07的存放目錄。
AutoDownLoadConfig Portlet 維護(hù)一個(gè)自動(dòng)下載的產(chǎn)品配置列表,在編輯模式下,用戶(hù)可以瀏覽并下載產(chǎn)品列表,查看一個(gè)選定的下載產(chǎn)品的詳細(xì)信息,也可以修改一個(gè)產(chǎn)品的配置信息。在配置模式下,用戶(hù)可以設(shè)置數(shù)據(jù)訪問(wèn)信息。雖然可用的數(shù)據(jù)源提供了包括配置模式在內(nèi)的完整的實(shí)現(xiàn),但為了滿(mǎn)足設(shè)計(jì)目的,我們只需注意查看和編輯模式的實(shí)現(xiàn)即可。自動(dòng)下載Portlet狀態(tài)模式示意圖如圖1-1所示。
圖1-1 自動(dòng)下載Portlet狀態(tài)模式示意圖
1.以基于MVC架構(gòu)的思路整理Portlet的邏輯
從可視的角度看,圖1-1所示的場(chǎng)景功能的實(shí)現(xiàn)至少需要如下頁(yè)面。
— 主視圖頁(yè)面(Main View Page)——顯示所有正在下載的產(chǎn)品列表和用來(lái)選擇一個(gè)產(chǎn)品以獲取更多詳細(xì)信息的選項(xiàng)。
— 詳細(xì)信息視圖頁(yè)面(Detail View Page)——顯示被選擇產(chǎn)品的詳細(xì)配置信息。
— 主編輯頁(yè)面(Main Edit Page)——顯示用戶(hù)有權(quán)限編輯的產(chǎn)品列表和用于修改更多信息的選項(xiàng)。
— 修改條目頁(yè)面(Modify Entry Page)——顯示相似的表單,其中插入了現(xiàn)有的數(shù)據(jù)用于修改,包括修改單項(xiàng)參數(shù),以及給某一參數(shù)增刪條目列表。
在這種情況下,用戶(hù)可以從主編輯頁(yè)面中選擇需編輯的產(chǎn)品條目。修改后,沒(méi)有確認(rèn)頁(yè)面或成功執(zhí)行的頁(yè)面。進(jìn)行條目修改處理并刷新主編輯頁(yè)面,若出錯(cuò),則顯示適當(dāng)?shù)南?/span>,但在正常處理時(shí),沒(méi)有與該操作關(guān)聯(lián)的視圖。
如何來(lái)改進(jìn)這個(gè)實(shí)現(xiàn)呢?首先,請(qǐng)記住這個(gè)應(yīng)用程序表示一組應(yīng)用程序操作和狀態(tài);其次操作是實(shí)現(xiàn)操作接口的類(lèi),這個(gè)類(lèi)實(shí)際完成某個(gè)應(yīng)用程序任務(wù)或操作處理。這就是目前存在于 actionListener 類(lèi)的 actionPerformed 方法中的應(yīng)用程序代碼的一部分,只有這部分特定于單個(gè)操作事件。
狀態(tài)是實(shí)現(xiàn)狀態(tài)接口的類(lèi),這個(gè)類(lèi)表示由于應(yīng)用了操作而產(chǎn)生的 Portlet 的效果。一般來(lái)說(shuō),這個(gè)類(lèi)有可視組件。
2.Portlet所包含的內(nèi)容
根據(jù)以上分析,我們將有下面這些操作。
— 所有產(chǎn)品配置信息的主列表視圖。
— 顯示選定產(chǎn)品的配置詳細(xì)信息視圖。
— 顯示所有可編輯產(chǎn)品的編輯視圖列表。
— 顯示視圖來(lái)修改一個(gè)產(chǎn)品的配置信息。
— 為產(chǎn)品添加一個(gè)可選的下載項(xiàng)或郵件。
— 為產(chǎn)品刪除一個(gè)可選的下載項(xiàng)或郵件。
執(zhí)行這些操作會(huì)產(chǎn)生下列狀態(tài)之一。
— 主視圖。
— 詳細(xì)信息視圖。
— 主編輯視圖。
— 添加下載產(chǎn)品視圖。
— 修改下載產(chǎn)品視圖。
從可視角度看,下載產(chǎn)品列表 Portlet 的實(shí)現(xiàn)包括如下視圖(頁(yè)面)。
(1)主視圖(Main View)——顯示下載產(chǎn)品列表,并帶有選項(xiàng)來(lái)選擇下載產(chǎn)品以查看更多的信息。
(2)詳細(xì)信息視圖(Detail View)——顯示選定的下載產(chǎn)品的詳細(xì)信息。
(3)主編輯視圖(Main Edit View)——顯示下載產(chǎn)品列表,并帶有選項(xiàng)來(lái)添加、刪除和修改下載產(chǎn)品信息。
(4)添加下載產(chǎn)品視圖(Add Contact View)——顯示表單視圖來(lái)輸入新下載產(chǎn)品的信息。
(5)修改下載產(chǎn)品視圖(Modify Contact View)——顯示相似的表單視圖來(lái)添加現(xiàn)有的下載產(chǎn)品的元素?cái)?shù)據(jù)以供修改。
下面以圖示的方式來(lái)介紹程序的數(shù)據(jù)流轉(zhuǎn)。
在顯示模式下,Portlet會(huì)從遠(yuǎn)程pvcent07.cn.ibm.com拷回XML文件,讀出并顯示所有正在下載的產(chǎn)品列表。單擊列表中的任意項(xiàng),將顯示該項(xiàng)的詳細(xì)視圖。我們先來(lái)看產(chǎn)品下載列表,如圖1-2所示。
圖1-2 產(chǎn)品下載列表
單擊任意產(chǎn)品的鏈接后,將顯示該產(chǎn)品的具體配置參數(shù),如圖1-3所示。
圖1-3 產(chǎn)品的具體配置參數(shù)
在編輯模式下,首先顯示的是用戶(hù)有權(quán)限編輯的產(chǎn)品配置列表,如圖1-4所示。
圖1-4 用戶(hù)有權(quán)限編輯的產(chǎn)品配置列表
單擊任意產(chǎn)品的鏈接,進(jìn)入到該產(chǎn)品的編輯界面,如圖1-5所示。
圖1-5 產(chǎn)品的編輯界面
用戶(hù)可以為該產(chǎn)品添加CD介質(zhì),或者添加一個(gè)E-mail,如圖1-6所示。
圖1-6 為產(chǎn)品添加要下載的CD介質(zhì)
當(dāng)然,用戶(hù)也可以刪除要下載的CD介質(zhì)或者E-mail,如圖1-7所示。
圖1-7 刪除要下載的CD介質(zhì)
用戶(hù)可以修改任意參數(shù),然后單擊“Save To XML”按鈕,Portlet將把這些參數(shù)保存到XML文件,并傳回到pvcent機(jī)器,如圖1-8所示。
圖1-8 將修改保存到Portlet配置文件
確認(rèn)修改保存成功,如圖1-9 所示。
圖1-9 確認(rèn)修改保存成功
1.StateManagerPortlet
StateManagerPortlet是主要的Portlet類(lèi),是Portlet無(wú)關(guān)的,一般包括所有特定于 Portlet 的代碼。該類(lèi)被用作分派器以支持駐留著Portlet 代碼的操作和狀態(tài)類(lèi)。StateManagerPortlet實(shí)現(xiàn)了actionPerformed、doView、doEdit、doHelp和doConfigure方法。
actionPerformed方法只是獲取操作類(lèi)的當(dāng)前實(shí)例,然后分派到它的actionPerformed方法中。類(lèi)似地,do方法獲取當(dāng)前的狀態(tài)對(duì)象,然后分派到它的perform方法中。所以,StateManagerPortlet 不需要知道當(dāng)前Portlet實(shí)現(xiàn)的任何細(xì)節(jié),也沒(méi)有大量用來(lái)確定下一步處理的if和檢查。只要你熟悉狀態(tài)與操作之間的流程,處理就能正確地進(jìn)行,而不必編寫(xiě)太多的、多余的控制邏輯代碼。
2.ActionClassManager
在WebSphere Portal中,ActionClassManager方法把Action類(lèi)實(shí)例添加到已棄用的PortelURI中。這個(gè)API是有用的,因?yàn)?/span>你可以從PortletEvent對(duì)象中檢索Action子類(lèi)實(shí)例,并把該實(shí)例作為狀態(tài)轉(zhuǎn)換的一部分分派到它的actionPerformed方法中。推薦的API將使用字符串而不是Action來(lái)添加到PortletURI,并且從Portlet Event 中進(jìn)行檢索。ActionClassManager類(lèi)提供了從給定的字符串到Action 類(lèi)的實(shí)例映射。
— Action
實(shí)現(xiàn)這個(gè)接口的類(lèi)將實(shí)現(xiàn)actionPerformed方法,該方法可執(zhí)行任何操作以實(shí)現(xiàn)操作請(qǐng)求所需的函數(shù)。但是,實(shí)現(xiàn)的函數(shù)特定于正被調(diào)用的操作事件。某個(gè)操作類(lèi)的個(gè)別的actionPerformed方法僅包含該操作的代碼,該方法還為進(jìn)一步的處理設(shè)置當(dāng)前狀態(tài)。在這個(gè)流程中,操作被調(diào)用后,它進(jìn)行特定于其函數(shù)的工作,然后為下一次轉(zhuǎn)換設(shè)置狀態(tài)。
— InitialStateManager
該類(lèi)為支持的每個(gè) Portlet方式提供初始狀態(tài)。
— State
一般來(lái)說(shuō),State的perform方法將調(diào)用JSP來(lái)顯示它的結(jié)果。用戶(hù)接口可能讓用戶(hù)來(lái)設(shè)置Portlet中的其他操作。JSP使操作類(lèi)與頁(yè)面上的每個(gè)操作關(guān)聯(lián)。在用戶(hù)調(diào)用其中的一個(gè)操作時(shí),StateManagerPortlet的actionPerformed方法將調(diào)用合適的操作類(lèi)實(shí)例,接著發(fā)生了狀態(tài)轉(zhuǎn)換。狀態(tài)類(lèi)并不負(fù)責(zé)狀態(tài)管理和轉(zhuǎn)換。
實(shí)現(xiàn)這個(gè)接口的類(lèi)需實(shí)現(xiàn)perform方法,該方法可被StateManagerPortlet的do方法調(diào)用,它包含一般駐留在這些方法中的代碼。同樣,這些代碼特定于它們所在類(lèi)的狀態(tài),從而降低了復(fù)雜性。
我們所創(chuàng)建的各個(gè)類(lèi)的功能分別簡(jiǎn)單介紹如下。
1.State類(lèi)功能邏輯介紹
子類(lèi)1:ActionClassManager類(lèi)
ActionClassManager類(lèi)負(fù)責(zé)返回一個(gè)操作子類(lèi)實(shí)例,該實(shí)例給出一個(gè)類(lèi)標(biāo)識(shí)符,這個(gè)標(biāo)識(shí)符是通過(guò) addAction(字符串)方法添加到 PortletURI中的。我們遵循如下約定:使類(lèi)標(biāo)識(shí)符為全限定類(lèi)名,這樣我們就能夠很容易地創(chuàng)建一個(gè)類(lèi)的實(shí)例。然而,我們可以通過(guò)單獨(dú)處理操作子類(lèi)實(shí)例來(lái)避免不必要的對(duì)象創(chuàng)建,然后需要ActionClassManager為所引用的操作子類(lèi)返回單一的實(shí)例。
子類(lèi)2:ActionPerformed類(lèi)
抽象的操作類(lèi)定義了兩個(gè)抽象的方法,因此它的子類(lèi)必須實(shí)現(xiàn) actionPerformed 方法和 setState 方法。當(dāng) StateManagerPortlet 類(lèi)從它的 actionPerformed 方法分派處理時(shí),操作子類(lèi)的 actionPerformed 方法得到調(diào)用。
setState方法也可由 StateManagerPortlet調(diào)用,確保操作子類(lèi)的實(shí)現(xiàn)在該用戶(hù)請(qǐng)求的操作處理完成之后設(shè)置下一個(gè)狀態(tài)。操作類(lèi)實(shí)現(xiàn)它自己的setState方法,子類(lèi)必須調(diào)用該方法來(lái)真正設(shè)置下一個(gè)狀態(tài)。這確保了操作類(lèi)和狀態(tài)類(lèi)知道在哪個(gè)類(lèi)設(shè)置和恢復(fù)下一個(gè)狀態(tài),而不需要子類(lèi)知道這些機(jī)制。這些狀態(tài)跨HTTP請(qǐng)求,并維持在每種Portlet模式下。所以,當(dāng)用戶(hù)改變模式時(shí),控制返回到最近一次訪問(wèn)的狀態(tài)。
子類(lèi)3:MainViewAction操作類(lèi)
MainViewAction 類(lèi)并不需要任何特定的操作處理。事實(shí)上,我們需要將下載產(chǎn)品列表顯示在主視圖上。我們能夠?qū)崿F(xiàn)在actionPerformed方法中創(chuàng)建恰當(dāng)?shù)南螺d產(chǎn)品列表Bean的代碼,將該代碼設(shè)置在會(huì)話(huà)或請(qǐng)求對(duì)象里,然后將下一個(gè)狀態(tài)設(shè)置到MainViewState里。子類(lèi) performView implementation繼承MainViewAction操作類(lèi),能夠簡(jiǎn)單地調(diào)用JSP,并提交來(lái)自會(huì)話(huà)或請(qǐng)求的Bean里的列表內(nèi)容。然而,我們必須注意門(mén)戶(hù)頁(yè)面更新,以防更新時(shí)調(diào)用的是Portlet的MainViewState、performView方法,而非MainViewAction的actionPerformed方法。所以,我們不能只是將Bean放置于請(qǐng)求對(duì)象里,而沒(méi)有讓 performView 方法重新創(chuàng)建該Bean,并將新的Bean放在該請(qǐng)求對(duì)象里。我們可以在會(huì)話(huà)里再次使用該Bean。但如果那樣做的話(huà),數(shù)據(jù)將會(huì)過(guò)時(shí)。如果我們?cè)诰庉嬆J较伦隽俗儎?dòng),就需要通知該變化,并在 State 方法里刷新數(shù)據(jù)Bean。為了簡(jiǎn)化這種處理,我們會(huì)只為 MainViewState 在 State 方法里得到數(shù)據(jù) Bean。
所以,在 MainViewState 類(lèi)里,actionPerformed方法并沒(méi)有另外處理,只是簡(jiǎn)單地設(shè)置了MainViewState而已。
子類(lèi)4:StateManagerPortlet類(lèi)
當(dāng)actionPerformed 完成處理時(shí),控制返回到門(mén)戶(hù)容器,以便其他的偵聽(tīng)器通知處理程序執(zhí)行。然后,門(mén)戶(hù)容器通過(guò)調(diào)用 StateManagerPortlet 的 service 方法繼續(xù) Portlet 請(qǐng)求處理。
StateManagerPortlet 的 service 方法首先試圖檢索以前執(zhí)行的操作類(lèi)設(shè)置的狀態(tài)類(lèi),如果沒(méi)有發(fā)現(xiàn)狀態(tài)類(lèi)引用(例如,最初的 Portlet 調(diào)用),那么就使用一個(gè)助手類(lèi) InitialStateManager 來(lái)為每種Portlet 模式確定初始的狀態(tài)類(lèi)。InitialStateManager 有一個(gè)唯一的方法叫做 getInitialState,它根據(jù) Portlet 的當(dāng)前模式返回狀態(tài)對(duì)象的一個(gè)實(shí)例。對(duì)于下載產(chǎn)品列表 Portlet,這個(gè)類(lèi)將為視圖模式返回 MainViewState 的一個(gè)實(shí)例。
State接口有一個(gè)唯一的方法 performView,所有的狀態(tài)類(lèi)都必須實(shí)現(xiàn)它。StateManagerPortlet 的 service 方法調(diào)用這個(gè)方法。
子類(lèi)5:MainViewState 類(lèi)
MainViewState 的 performView 方法負(fù)責(zé)在 Contacts Bean 的列表表單中獲取下載產(chǎn)品列表,下載產(chǎn)品列表保存在數(shù)據(jù)庫(kù)里,然后傳遞到 JSP 以便在主視圖中呈現(xiàn)出來(lái)。
子類(lèi)6:MainViewState 類(lèi)
這個(gè)子類(lèi)允許用戶(hù)單擊一個(gè)下載產(chǎn)品條目,然后顯示該下載產(chǎn)品的詳細(xì)信息視圖。
用于這個(gè)標(biāo)記的 href 使用來(lái)自Portlet標(biāo)記庫(kù)中的createURI標(biāo)記。該標(biāo)記在URIAction中獲得參數(shù),而URIAction被我們?cè)O(shè)置為操作類(lèi)中用于用戶(hù)單擊操作的事件處理方法的名稱(chēng)。
子類(lèi)7:actionPerformed
actionPerformed類(lèi)用來(lái)查看JSP上顯示的主要清單。用戶(hù)可以從主視圖頁(yè)面選擇特定的下載產(chǎn)品條目來(lái)獲得詳細(xì)信息。我們還添加了一個(gè)錨標(biāo)記將下載產(chǎn)品條目的名稱(chēng)作為可點(diǎn)擊的鏈接顯示出來(lái),當(dāng)點(diǎn)擊時(shí),StateManagerPortlet的 actionPerformed 方法被DetailViewAction 類(lèi)調(diào)用。
actionPerformed方法得到所選擇的下載產(chǎn)品條目的對(duì)象id,并調(diào)用持久性類(lèi)的代理為該id獲取實(shí)例化的下載產(chǎn)品對(duì)象。這個(gè)下載產(chǎn)品對(duì)象放在State類(lèi)的會(huì)話(huà)中,用來(lái)呈現(xiàn)詳細(xì)信息視圖。如果該頁(yè)面由于門(mén)戶(hù)頁(yè)面刷新而得以刷新,那么該Bean就將在會(huì)話(huà)中可用,既然該對(duì)象只會(huì)通過(guò)用戶(hù)使用 Portlet 來(lái)獲得更新,我們就不必?fù)?dān)心數(shù)據(jù)過(guò)時(shí)了。
門(mén)戶(hù)頁(yè)面刷新的另一個(gè)關(guān)鍵之處是表單數(shù)據(jù)沒(méi)有被重新初始化。如果我們?cè)噲D獲得所選下載產(chǎn)品的對(duì)象id作為狀態(tài)類(lèi)的請(qǐng)求參數(shù),它在門(mén)戶(hù)頁(yè)面刷新時(shí)將不可用。因此,為了使 Portlet 能正常運(yùn)行,必須在剛開(kāi)始時(shí)就檢索數(shù)據(jù)元素,然后將其存儲(chǔ)在某個(gè)地方,這樣在隨后的頁(yè)面刷新時(shí)它才可以被引用。由于 actionPerformed 方法曾被調(diào)用,所以這就是存放這段代碼的好地方。
在actionPerformed方法中保留后端數(shù)據(jù)訪問(wèn),可以確保我們?cè)陧?yè)面刷新時(shí)對(duì)于同一數(shù)據(jù)不需要多次訪問(wèn)數(shù)據(jù)庫(kù)。當(dāng)然,返回到數(shù)據(jù)源進(jìn)行數(shù)據(jù)刷新的時(shí)間和頻率取決于Portlet的需求,以及數(shù)據(jù)本身的因素。在這種情況下,數(shù)據(jù)不是動(dòng)態(tài)的,當(dāng) Portlet 頁(yè)面被刷新時(shí),應(yīng)該對(duì)其進(jìn)行高速緩存。
最后,DetailViewState 被設(shè)置為這個(gè)Portlet的下一個(gè)狀態(tài),對(duì)于Portlet,其中的處理將繼續(xù)。
子類(lèi)8:DetailViewState 類(lèi)
DetailViewState 簡(jiǎn)單地調(diào)用JSP來(lái)呈現(xiàn)詳細(xì)信息視圖,JSP 從會(huì)話(huà)中獲取下載產(chǎn)品 Bean。在UI交互界面中,當(dāng)用戶(hù)單擊“OK”按鈕時(shí),處理返回到主視圖繼續(xù)進(jìn)行。MainViewAction的actionPerformed 方法通過(guò)刪除我們?cè)?DetailViewAction 類(lèi)中設(shè)置的下載產(chǎn)品對(duì)象 id 來(lái)簡(jiǎn)單地刪除會(huì)話(huà)數(shù)據(jù)。
子類(lèi)9:ViewProductAction類(lèi)
ViewProductAction類(lèi)用來(lái)顯示下載產(chǎn)品詳細(xì)信息視圖的JSP頁(yè)面。流邏輯以一種組織良好的方式進(jìn)行,你不需要在Portlet中使用煩冗的控制代碼。Portlet 的編輯和配置模式也以同樣的方法實(shí)現(xiàn)。
2.完成Portlet實(shí)現(xiàn)
該應(yīng)用程序的其余部分仍遵循以上所述的開(kāi)發(fā)模式。編輯模式的處理控制邏輯流和視圖模式的完全一樣。我們實(shí)現(xiàn)一種配置模式,它允許用戶(hù)指定數(shù)據(jù)源來(lái)保存下載產(chǎn)品數(shù)據(jù)。它將以同樣的方式實(shí)現(xiàn)。配置模式只有一個(gè)視圖來(lái)讓用戶(hù)訪問(wèn)數(shù)據(jù)源,另外有兩個(gè)類(lèi)來(lái)檢驗(yàn)數(shù)據(jù)源和保存數(shù)據(jù)源為配置數(shù)據(jù)。
下面是實(shí)現(xiàn)狀態(tài)模式的基本步驟。
所執(zhí)行的特定模式的初始狀態(tài)類(lèi)由 InitialStateManager 類(lèi)提供。
狀態(tài)類(lèi)的 performView方法(其調(diào)用是由 StateManagerPortlet 分派的)進(jìn)行任何必要的應(yīng)用程序邏輯處理,然后調(diào)用它的 JSP。
通過(guò)PortletURI上的一個(gè)參數(shù)將每個(gè)用戶(hù)的操作與在其中進(jìn)行事件處理的操作子類(lèi)的名稱(chēng)相關(guān)聯(lián)。每個(gè)用戶(hù)操作一般都指定一個(gè)不同的操作子類(lèi),該子類(lèi)實(shí)現(xiàn)一個(gè)單一的、特定的功能。
當(dāng)用戶(hù)單擊一個(gè)鏈接時(shí),操作類(lèi)的 actionPerformed 方法被調(diào)用(由于通過(guò) StateManagerPortlet 分派而被再次調(diào)用)。執(zhí)行操作邏輯,并設(shè)置適當(dāng)?shù)臓顟B(tài)類(lèi)以使處理繼續(xù)進(jìn)行。
當(dāng)事件處理完成后,StateManagerPortlet的service方法被調(diào)用,并再次分派給在Action事件處理階段設(shè)置的狀態(tài)類(lèi),該狀態(tài)類(lèi)執(zhí)行應(yīng)用程序邏輯并調(diào)用它的 JSP 來(lái)呈現(xiàn)結(jié)果。
當(dāng)用戶(hù)瀏覽整個(gè) Portlet 時(shí),操作以這種方式繼續(xù)。
3.持久性代理
訪問(wèn)數(shù)據(jù)庫(kù)中的持久性數(shù)據(jù)需要額外的 Portlet 組件。AbstractBroker 類(lèi)提供了一般的JDBC數(shù)據(jù)庫(kù)訪問(wèn)功能。它能夠用來(lái)獲取數(shù)據(jù)庫(kù)的DataSource和Connection;它在高速緩存中緩存DataSource,從而避免重復(fù)的、高代價(jià)的JNDI查找;它也提供通用代碼來(lái)執(zhí)行 PreparedStatement,并關(guān)閉Connection、Statement和ResultSet。
ContactListBroker 類(lèi)繼承了 AbstractBroker,它實(shí)現(xiàn)了特定于 Portlet 需要的數(shù)據(jù)訪問(wèn)方法,如 getContact 方法和 getContactList 方法,用于保存或刪除一個(gè)列表中的條目。同時(shí)它還有檢驗(yàn)表 Schema 的功能,這樣我們就可以檢驗(yàn)用戶(hù)在配置模式下指定的數(shù)據(jù)源。
4.異常處理
我們已經(jīng)為Portlet 實(shí)現(xiàn)了大量的異常類(lèi),基本類(lèi)是AIMException,AIMWrapperException是AIMException 的子類(lèi)。你可以用 AIMWrapperException 封裝其他拋出的異常,以便在 StateManagerPortlet的service 方法中高效地修改顯示行為和管理異常處理。
AIMMessageException 是一個(gè)特殊的異常,它允許在終止處理時(shí)向 Portlet 生成一條報(bào)告性消息或錯(cuò)誤消息。例如,可以?huà)伋鲆粋€(gè) AIMMessage 異常,用一條消息指出用戶(hù)必須先登錄。
actionPerformed方法或setState方法中拋出的異常被捕獲,并且被延遲到 service 方法。管理延遲的方法是捕獲這些方法中拋出的所有異常,并將異常(通常封裝在一個(gè)AIMWrapperException中)放在請(qǐng)求對(duì)象上。當(dāng)調(diào)用StateManagerPortlet的service方法時(shí),它首先查找有沒(méi)有延遲異常,如果找到了,就從此處重新拋出并處理這些異常。
因此,所有的Portlet應(yīng)用程序異常都是在 StateManagerPortlet的service方法中處理的。如果發(fā)現(xiàn)了異常,則在以下兩種情況中調(diào)用異常方法:異常消息將在Portlet中被顯示;異常消息以及相關(guān)聯(lián)的堆棧跟蹤信息將被顯示。將堆棧跟蹤信息放在 Portlet 外有助于在開(kāi)發(fā)時(shí)進(jìn)行調(diào)試。由于不想向?qū)嶋H應(yīng)用的用戶(hù)顯示這種級(jí)別的詳細(xì)信息,所以該行為是可配置的。這是在部署描述符里定義的 debugTrace參數(shù)。
5.建立開(kāi)發(fā)環(huán)境
如果你使用WebSphere Studio來(lái)創(chuàng)建這個(gè)Portlet,請(qǐng)確保下列JAR文件的構(gòu)建路徑是可用的,以便Portlet代碼可以順利編譯。如果你在Studio中使用Portal Toolkit并創(chuàng)建Portlet應(yīng)用項(xiàng)目,那么類(lèi)路徑會(huì)自動(dòng)創(chuàng)建。不管哪種情況,你都可以創(chuàng)建一個(gè)Web項(xiàng)目或Portlet應(yīng)用項(xiàng)目,然后導(dǎo)入下載中的WAR文件,從而將這個(gè)Portlet應(yīng)用程序載入Studio。
SERVERJDK_50_PLUGINDIR/jre/lib/rt.jar
WAS_50_PLUGINDIR/lib/dynacache.jar
WAS_50_PLUGINDIR/lib/j2ee.jar
WAS_50_PLUGINDIR/lib/servletevent.jar
WAS_50_PLUGINDIR/lib/ivjejb35.jar
WAS_50_PLUGINDIR/lib/runtime.jar
WAS_50_PLUGINDIR/lib/ras.jar
WAS_50_PLUGINDIR/lib/naming.jar
WAS_50_PLUGINDIR/lib/utils.jar
WPS_V5_PLUGINDIR/portlet-api.jar
WPS_V5_PLUGINDIR/wpsportlets.jar
WPS_V5_PLUGINDIR/wps.jar
如果你沒(méi)有使用 Portal Toolkit或者Studio,那么可以在 <WAS_ROOT>/lib 和 <WPS_ROOT>/shared/app 中找到這些文件。
當(dāng)Portlet部署到WebSphere Portal 環(huán)境中時(shí),所有必需的JAR文件都要同時(shí)打包進(jìn)去。你可以不做修改,而是在 Portal 中安裝 Portlet WAR 文件。
針對(duì)入門(mén)者,我們以圖示的方式,向大家介紹使用IBM提供的開(kāi)發(fā)工具RAD(Rational Application Developer)來(lái)創(chuàng)建、開(kāi)發(fā)、調(diào)試、打包Portlet。
原則上我是按照安裝從始至終的次序來(lái)截圖的,但為了使層次更清晰,我們還是分為以下7個(gè)步驟來(lái)分別介紹。
1.安裝RAD,創(chuàng)建portlet
在Windows 2003 Server系統(tǒng)的“控制面板”→“高級(jí)”選項(xiàng)中,單擊“設(shè)置”按鈕,在出現(xiàn)的對(duì)話(huà)框中選擇“數(shù)據(jù)執(zhí)行保存”面板,單擊“添加...”按鈕,把安裝后的rationalsdp.exe和enroll.exe 添加到列表中。
打開(kāi)RAD,單擊“新建”按鈕,選擇“項(xiàng)目”→“Portlet項(xiàng)目”,然后依次輸入各項(xiàng)參數(shù),包括Portlet的名稱(chēng)、包名、是否使用憑證保險(xiǎn)庫(kù)等。
參數(shù) 值
Portlet 名稱(chēng) DownLoadConfig
Portlet 類(lèi)型 基本Portlet
Web功能部件 使用Web圖與JSP標(biāo)記庫(kù)
是否需要添加操作偵聽(tīng)實(shí)例 不需要
是否需要添加憑證保險(xiǎn)庫(kù) 不需要
使用模式 顯示模式、編輯模式、培植模式、幫助模式
單擊“完成”按鈕,Rational開(kāi)始自動(dòng)創(chuàng)建這個(gè)Portlet,創(chuàng)建完成后自動(dòng)打開(kāi)“DownLoadConfigView.jsp”文件,如圖1-10所示。
圖1-10 在RAD中開(kāi)發(fā)Portle
2.創(chuàng)建并設(shè)計(jì)所需的操作類(lèi)(Actions)
創(chuàng)建一個(gè)Action包:com.ibm.csdl.portal.download.config.actions,在這個(gè)包里分別創(chuàng)建以下類(lèi),如圖1-11所示。
圖1-11 創(chuàng)建的操作類(lèi)
這些類(lèi)實(shí)現(xiàn)了Portlet的所有操作,我們以“為產(chǎn)品配置刪去一個(gè)CD或者E-mail”為例,看一下Action實(shí)現(xiàn)了哪些功能。
在actionPerformed方法里,程序接收從editAProduct.jsp傳過(guò)來(lái)的參數(shù),也就是CDs和Emails兩個(gè)選擇框傳過(guò)來(lái)的值,看要?jiǎng)h除的是一個(gè)CD還是一個(gè)E-mail,然后從產(chǎn)品配置對(duì)象里面將對(duì)應(yīng)的CD或者E-mail刪除,最后寫(xiě)回到XML文件中。
在setState()方法里,程序?qū)嵗粋€(gè)RemoveOneCDsOrEmailState,將邏輯交給State來(lái)處理。那么,State又如何流轉(zhuǎn)呢?看下面的State類(lèi)。
3.創(chuàng)建并開(kāi)發(fā)所需的狀態(tài)類(lèi) (States)
創(chuàng)建一個(gè)State包:com.ibm.csdl.portal.download.config.actions,在這個(gè)包里分別創(chuàng)建以下類(lèi),如圖1-12所示。
圖1-12 創(chuàng)建的狀態(tài)類(lèi)
這些類(lèi)實(shí)現(xiàn)了Portlet的所有狀態(tài)模式轉(zhuǎn)換,我們以“為產(chǎn)品配置刪去一個(gè)CD或者E-mail”為例,看一下State實(shí)現(xiàn)了哪些功能。
RemoveOneCDsOrEmailState.java代碼清單如下:
State類(lèi)里面只有兩個(gè)方法,其中一個(gè)方法用于獲得實(shí)例,我們就不管了;另一個(gè)方法是performView,它負(fù)責(zé)讀出XML文件里的內(nèi)容(現(xiàn)在已經(jīng)是修改后的了),然后放入Session,調(diào)用并初始化一個(gè)新的指定的JSP文件。這個(gè)JSP從Session里面取出數(shù)據(jù),然后初始化。
4.創(chuàng)建并開(kāi)發(fā)所需的數(shù)據(jù)結(jié)構(gòu)(Data)以及Portlet類(lèi)
Data類(lèi)主要定義了一些數(shù)據(jù)結(jié)構(gòu),用來(lái)存放XML文件中的數(shù)據(jù),與Portlet的開(kāi)發(fā)基本上無(wú)關(guān)。
Portlet類(lèi)主要用來(lái)初始化一些數(shù)據(jù),以及根據(jù)Portlet的狀態(tài)調(diào)用相應(yīng)的JSP頁(yè)面。
nls下的資源文件與瀏覽器的多語(yǔ)言支持相關(guān),可以根據(jù)客戶(hù)端瀏覽器的設(shè)置,從相應(yīng)的資源里取出靜態(tài)描述文件Portlet.xml,然后在JSP文件中完成初始化的過(guò)程。
com.ibm.csdl.portal.download.config.utilities包主要處理一些異常(見(jiàn)圖1-13),這里不再贅述。
圖1-13 com.ibm.csdl.portal.download.config.utilities中默認(rèn)帶有常見(jiàn)的異常處理邏輯
5.創(chuàng)建并開(kāi)發(fā)所需的頁(yè)面(Pages)
根據(jù)上面的詳細(xì)設(shè)計(jì),我們需要?jiǎng)?chuàng)建一些頁(yè)面,如圖1-14所示。
圖1-14 創(chuàng)建的頁(yè)面
這些頁(yè)面的功能如下。
頁(yè)面的顯示邏輯略。我們以ViewAllTheProduct.jsp為例,看一下Rational是怎樣給一個(gè)鏈接添加操作事件偵聽(tīng)的。
ViewAllTheProduct.jsp源代碼如下:
其實(shí)很簡(jiǎn)單,用一個(gè)超鏈接就能添加該鏈接的操作事件偵聽(tīng),代碼如下:
其他的類(lèi)似,這里不再贅述。
6.調(diào)試 Portlet
假設(shè)在9.181.66.250上運(yùn)行著一個(gè)Portal系統(tǒng),超級(jí)管理員的用戶(hù)名和密碼都是admin,我們可以創(chuàng)建一個(gè)服務(wù)器用來(lái)測(cè)試Portlet,如圖1-15所示。
圖1-15 在RAD中創(chuàng)建Portal服務(wù)器用于調(diào)試Portlet
選擇服務(wù)器的類(lèi)型為WebSphere Portal,并輸入相關(guān)參數(shù)。
右擊項(xiàng)目名,選擇“運(yùn)行”→“在服務(wù)器上運(yùn)行”,如圖1-16所示。
圖1-16 選擇直接在RAD中運(yùn)行Portlet
幾分鐘后,會(huì)在工作區(qū)出現(xiàn)瀏覽頁(yè)面,這樣就可以調(diào)試該Portlet了。
7.打包,生成產(chǎn)品
打包Portlet也非常簡(jiǎn)單,右擊項(xiàng)目名,選擇“導(dǎo)出”→“WAR文件”,再選擇好存儲(chǔ)位置就可以了,如圖1-17所示。
圖1-17 將Portlet導(dǎo)出為WAR包部署到Portal服務(wù)器
拿這個(gè)WAR包,就可以發(fā)布或者更新到Portal系統(tǒng)上使用了。
熟悉Portlet 開(kāi)發(fā)指導(dǎo)原則和示例實(shí)現(xiàn)可以對(duì)Portlet API有很好的理解。然而,實(shí)現(xiàn)復(fù)雜的流程控制超出了 API 的范圍。如果沒(méi)有定義完善的方法來(lái)解決如何最好地實(shí)現(xiàn)控制邏輯這一問(wèn)題,你就不能夠創(chuàng)建這樣的Portlet——它們包含有專(zhuān)門(mén)定位用戶(hù)請(qǐng)求目的的簡(jiǎn)單合理的 代碼。
除了重復(fù)之外,該代碼使Portlet更難以讀懂,因?yàn)?/span>你需要進(jìn)入控制邏輯以獲取Portlet正在做的實(shí)際工作??刂七壿嬕踩菀壮鲥e(cuò),因?yàn)樗蕾?lài)于多方面情況,比如,使用字符串匹配用來(lái)連接事件和偵聽(tīng)器,或者偵聽(tīng)器操作和 Portlet 方法中的Action。為了解決控制邏輯的這些問(wèn)題,你可以將應(yīng)用程序看做是Portlet的操作和狀態(tài)的集合,然后通過(guò)一個(gè)定義完善的方法來(lái)進(jìn)行狀態(tài)轉(zhuǎn)換,這樣你就可以將Portlet應(yīng)用程序中煩冗的控制邏輯代碼刪除。
開(kāi)發(fā)人員也可以選擇采用Struts框架來(lái)實(shí)現(xiàn)Portlet。Struts是一個(gè)Jakarta項(xiàng)目,它提供一個(gè)非常流行的開(kāi)放源代碼框架來(lái)建立 Web 應(yīng)用程序。使用附帶了 Portal 的 Struts Portlet Framework,用Struts框架寫(xiě)成的Portlet就可以在WebSphere Portal上運(yùn)行。Struts提供了值得考慮的Web應(yīng)用程序,其功能遠(yuǎn)遠(yuǎn)超過(guò)頁(yè)面導(dǎo)航,它是進(jìn)行Portlet開(kāi)發(fā)的一個(gè)很好的選擇。對(duì)Struts不熟悉或者希望更直接訪問(wèn) Portlet API 的開(kāi)發(fā)人員會(huì)從用于頁(yè)面導(dǎo)航的狀態(tài)轉(zhuǎn)換實(shí)現(xiàn)中獲益。這種模式和Struts框架一樣,使面向MVC設(shè)計(jì)的應(yīng)用程序框架得以改進(jìn)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。