摘要
門戶應用程序非常適用于從多個源提取信息以及為包含門戶web應用程序的portlet提供應用服務。對于用戶,portlet應用程序是獨立的實體,類似于桌面上的窗口應用程序。如果在一個窗口應用程序中執行一項操作會導致其他所有應用程序中的內容被刷新,那又會怎么樣呢?這就是當前大多數門戶的情況。在一個portlet中通過頁面流進行轉移會導致整個web頁面被刷新,包括該頁面上的其他所有portlet。
為了避免出現這種有時不希望有的行為,人員采用了所謂ajax-風格的編程方法。ajax即異步java和xml(asynchronous java and xml),它是一個技術的集合,包括用于創建交互式web應用程序的xhtml、css、javascript、dom和xmlhttprequest對象。本文將說明在bea weblogic portal環境中使用ajax編程方法的基本原理,并提供了一些最佳實踐和建議,以避免新手ajax程序員經常會犯的許多錯誤。
ajax簡介
考慮一個基于一些用戶標準(比如街道地址、城市和州,)來繪制街道地圖的web應用程序。這類應用程序在用戶界面中已經存在很多年了,并且很少有所改變。用戶輸入一個地址,然后單擊一個按鈕,頁面中心就會顯示周邊區域的地圖。用戶通常需要縮小和放大以更清楚地顯示周圍區域,或者需要把地圖向左或向右稍作移動,以找到一些能夠幫助他們進行定位的主要街道或地界標。訪問maps.yahoo.com或mapquest.com,便可以獲得這種體驗。來吧,試試這個地址:100 east wacker drive chicago, il
最終,您將看到一幅芝加哥市區的地圖,中心是wacker和michigan大街。在右方,您將看到一系列縮放級別,您可以從中選擇一個。當選定一個縮放級別之后,會出現什么情況呢?整個頁面將會刷新,這會花費相當長一段時間。現在,當您把地圖向左或向右移動時,又會出現什么情況呢?您不可避免地會刷新整個頁面,而整個地圖需要再次下載。頁面大小通常是75到100k,而平均的返回時間大約是3到10秒鐘,這取決于您的網絡連接速度。
現在使用google maps進行同樣的嘗試,這是一個完全使用ajax技術的站點。輸入地址,然后單擊search。頁面將完全顯示出來。現在進行縮放。注意,地圖之外的頁面內容不會刷新。下面列出了這背后所發生的事情:
注意,地圖上沒有指示東西南北的箭頭。用戶如何與地圖進行交互呢?只需像在一個滾動窗口中那樣進行拖拉即可。試著單擊地圖的中心,然后把地圖向左方拖動。注意拖動地圖時地圖是如何響應的!下面列出這背后所發生的事情:
下面是使用ajax技術所帶來的好處:
上面對于ajax風格的用戶界面的演示令人印象深刻。(如果在使用google maps數天之后,您還不相信其競爭對手已經惱羞成怒,那么您就不必閱讀本文下面的內容了。)
有關ajax的完整介紹,請閱讀an introduction to ajax(中文版,dev2dev,2005年11月)。
ajax所解決的門戶問題
考慮那些大量使用java applet而且希望利用其現有資產創建門戶的潛在客戶。把現有applet和其他頁面流包裝到portlet容器中是一件很簡單的事情,但是也要考慮到進行門戶測試時會出現哪些問題。例如,某個porlet中的一個動作會導致刷新以及隨后的重新加載,并重新初始化頁面上其他所有基于applet的portlet。如果所討論的applet具有后端連接,那么portlet的重新初始化將導致服務器丟棄現有連接,然后強制applet重新進行連接,這不僅加重了服務器的負擔,而且會使門戶用戶看到幾秒鐘的“靜止時間”,在這段時間內,基于applet的portlet必須保持灰色,一直到它們完成初始化為止。
這顯然是一個潛在的瑕疵。告訴客戶們重寫所有的applet,因為基于jsp的應用程序并非有用的響應,尤其是對于已經在現有資產中投入大量資源的客戶來說。此外,門戶必須幫助客戶包裝現有的應用程序,而不是強迫他們重寫整個系統。
我們需要一種讓單個portlet在不引起頁面刷新的情況下進行操作或獲得新數據的方法。雖然這顯然存在一些不利之處(我將在本文后面討論這些),但是在這種情況下,把避免頁面刷新作為使用門戶的進入屏障是完全有必要的。
注:對于這個問題,一個可行的解決方案是iframes,也就是inline frames,一種基于瀏覽器的機制,它可以使屏幕的一塊區域變為獨立的實體,當頁面重新加載時它不會刷新。使用類似于ajax編程中所使用的技術,我們可以使用xml-rpc進行服務器調用,從而獲取數據并將其加載到dom文檔中。apple的開發者web站點上有一篇文章非常好地總結了這種方法的優點和缺點。我確信,關于為什么iframes更好或ajax更好,雙方的支持者已經進行過精彩的辯論,但是ajax已經流行開來,而iframes則沒有。因此,本文只介紹了ajax,而沒有就iframes進行討論。
用例
在下列情形下,ajax技術很有用處:
示例架構
ajax技術的核心是web瀏覽器對一些負責提供信息的web服務的調用。如何為該解決方案設計架構呢?有3種值得考慮的架構。第一種架構使用web瀏覽器作為集成點,出于隨之而來的安全考慮和瀏覽器方面的問題,該架構存在問題。第二種解決方案使用代理來獲取分布的資源,這消除了安全問題,但是添加了一個單點故障。第三種架構使用企業服務總線(enterprise service bus,esb)來消除單點故障,并為web服務和ajax技術的蓬勃發展提供了最適宜的環境。
以瀏覽器為中心
在以瀏覽器為中心的架構中,web瀏覽器成為聯系遠程系統的中心點,如圖1所示。數據從各個遠程系統中獲得,然后在瀏覽器處的javascript中進行整理和排序。
圖 1.以瀏覽器為中心的架構
這種架構是最自然的設計,它具有多處設計缺陷:
代理服務
如圖2所示,代理服務消除了第一種架構的所有缺陷,但是它也有自己的不足之處。它導致出現了一個系統單點故障。當然,web服務器可以作為帶有硬件負載平衡器的集群的一部分。這無疑可以解決這個問題。
圖 2. 代理服務架構
盡管這種架構比起以瀏覽器為中心的架構已經有了巨大的改進,還可以做得更好。我們已經為人員提供了一個非常好的環境,但是這很可能為后端系統開發人員帶來不便。對遠程系統進行身份驗證以及數據整理仍然是必要的,但是至少后端程序員應該有更多可使用的工具來迎接挑戰。
企業服務總線
圖3與前面的兩幅圖又有所不同,因為企業服務總線(esb)架構是一種邏輯架構。服務可以位于網絡上的任意位置,數據源可以被抽象到(可插入到esb中的)服務中。esb為后端系統開發人員處理了他們通常必須做的工作,比如服務身份驗證、數據轉換、協議轉換和可靠性特征。esb可以擴展到帶有硬件負載平衡器的計算機集群上,這提供了代理服務架構所具有的優點。
圖 3.企業服務總線
為了說明在門戶中對ajax應用程序使用esb的優點,考慮對于每次ajax調用都要引用一個web服務的情況。對于小型門戶來說,web服務的數量可能相對較少,譬如說幾十個。但是隨著門戶的增長,將會引入更多的web服務。大量web服務的添加與ajax沒有關系,但是與soa的實現有著密切的聯系。這是一個esb的經典用例。盡管從嚴格意義上來說,它對于ajax實現的操作不是必要的,但是它還是帶來了幾個好處:
在這里的例子中,我之所以使用了以瀏覽器為中心的架構和代理服務架構,是因為作為例子來說,它們比較簡單,但是我希望能夠使您相信,ajax是體現esb優點的非常不錯的方式。
對門戶使用的影響
當在門戶內采用ajax編程方法時,出現了幾個問題。這些問題中的大多數與門戶的生命周期以及如何/何時挑選用戶信息有關。具體來說,門戶要使用諸如用戶在哪里單擊之類的信息來決定向其顯示何種類型的相關信息。weblogic portal具有一種叫做campaign的特性,它允許門戶設計人員基于用戶個人信息指定對用戶的有目的廣告宣傳。用戶個人信息中包括用戶的頁面歷史,即,用戶過去點擊過的頁面。門戶在頁面刷新時收集這類信息,所以如果用戶從未刷新頁面,門戶就無法(容易地)自動收集用戶信息。
考慮ajax編程可能對門戶產生的以下副作用:
使用適當的編碼風格可以防止這些問題的發生,比如給所有變量和函數取獨有的名稱,或者使用cookies來保存portlet中使用的當前數據。
一種最佳實踐是在所有腳本中使用獨有的變量和函數名稱,具體做法是在每個變量和函數的名稱前加上包含它們的portlet的名稱。
瀏覽器戰爭尚未結束,專有瀏覽器和基于標準的瀏覽器之間的戰爭仍在延續。ajax相當有趣的一點是,其中有一半是標準(xhtml、xslt、javascript/ecmascript、dom和web services)驅動的。但是其核心技術——xmlhttprequest對象——來自微軟。
下面列出了在進行跨瀏覽器的ajax編程時要注意的一些重要的常見錯誤,以及如何避免這些陷阱。
安全性
xmlhttprequest對象直接把瀏覽器連接到一臺遠程主機,要么是加載頁面的web服務器,要么是從另一個完全不同的服務器。正如您所想像的,這里為惡意軟件提供了大量的機會。例如,一段惡意的javascript可能等著用戶輸入口令字段,然后把口令傳遞給一個遠程瀏覽器,而用戶卻不知道,甚至還沒有單擊頁面上的提交按鈕。如果把口令換為信用卡號碼,事情就變得更加有趣了。
為了避免這種風險,mozilla拒絕到為web頁面提供服務的主機之外的任意主機的連接。用戶不會看到錯誤消息,因為它根本就不會運行!
internet explorer (ie)采用另一種方法。當要求連接到遠程主機時,將使用一個對話框通知用戶,而用戶可以決定執行什么操作。但是要注意,該對話框不會告訴用戶要連接到哪個站點,所以用戶缺乏可以用于做出決策的信息。
圖 4. 沒有有用的信息!
這個問題的解決方案是使用一個java servlet作為到web服務的代理。該servlet獲得所有的參數,并把它們傳遞給遠程服務,接著將響應返回給web站點。通過讓servlet運行在創建web頁面的web服務器上,mozilla就會認為服務是本地的。注意,這是企業服務總線(比如aqualogic service bus)的一個絕好用例。
使用xmlhttprequest對象
包含xmlhttprequest對象的xmlhttp庫最初是隨internet explorer 4一起發行的activex控件。mozilla包含一個兼容的函數庫,所以沒有什么好擔心的。我仍然推薦使用一個開源庫,比如sarissa或dwr。然而,它們在將xml數據傳遞到對象的方式上存在著細微的區別。
更新dom節點
mozilla和ie之間最令人惱火的區別就是web頁面中對dom(document object model,文檔對象模型)的處理。大多數函數的工作方式是一樣的(至少在dom level 2上),但是仍然有很多值得注意的地方。下面給出兩個例子。
innerhtml與innertext的使用
當使用新的動態內容更新<div>標簽時,ie用戶有兩個選擇:可以更新節點的innertext或innerhtml。二者的區別很細微,但是卻能在信息的顯示方面造成很大的差別,尤其是當要顯示的文本是xml格式或者包含html實體(比如尖括號或&符號)時。使用innerhtml時假定內容與標簽是一起放入的(不管內容是什么)。假設我們試著把以下文本放入一個節點中:
var txt = <b>this is a test</b> document.getelementbyid('mydivtext').innertext = txt; document.getelementbyid('mydivhtml').innerhtml = txt;
<div id="mydivhtml">部分在瀏覽器中看起來如下:
this is a test
<div id="mydivtext">部分看起來則是下面這樣:
<b>this is a test</b>
基本上,innertext節點對輸入字符串進行轉義,這樣顯示在用戶面前的就是內容原來的樣子。但是mozilla在dom節點上不支持innertext屬性,所以更好的方法是用戶親自對文本進行轉義,并始終使用innerhtml。sarissa有一個幫助器函數用于實現這一項功能:
document.getelementbyid('mydivtext').innerhtml = sarissa.escape("<b>this is a test</b>")
我們將得到同樣的結果,如下:
document.getelementbyid('mydivtext').innertext = "<b>this is a test</b>")
在門戶中使用獨有名稱
當某個門戶頁面由weblogic portal(或任何門戶)進行解析時,每個portlet均作為完整的web頁面放在html文檔中,包括<body>標簽(有時甚至包括<html>標簽)。因此,如果在每個portlet中始終以相同的id來命名<div>標簽(理論上來說,這似乎是使編程標準化的一種良好方法),那么將獲得不正確的結果。考慮如果有兩個id為“result_data”的元素,那么解析后的門戶頁面將會是什么樣子。
// outer portal shell <html> // first portlet ... <div id="result_data"></div> ... // second portlet ... <div id="result_data"></div> ... </html>
現在,進行一次如下的調用:
document.getelementbyid('result_data').innertext = "stuff";
哪個元素將被更新呢?答案基本上會隨瀏覽器的不同而不同,但是一般的答案就是“第一個”。
因此,這里的最佳實踐是使用portlet名稱作為html標簽中所有id的前綴。
結束語
傳統的web應用程序已經無法滿足客戶的要求。由于google之類的公司提供了更新、更快和交互性更強的web站點,客戶的期望值變得越來越高。構建使客戶可以提高工作速度和效率的用戶界面始終是一項戰略性挑戰。
ajax編程是web應用程序交互方面的新的事實標準,它為緊密耦合的數據和應用程序筒倉提供了部分解決方案。特別是在與bea weblogic平臺結合使用時,ajax代表了web編程的未來方向,并預示著構建具有高度的交互性和響應靈敏度的web站點的新潮流。
在本系列的第二部分中,我將使用具體的例子說明如何在weblogic portal環境中使用ajax。具體來說,我將演示大量portlet,以說明如何從javascript調用web服務以及使用結果更新頁面、如何實現代理servlet來處理對外部web服務的調用、如何使用ajax把web頁面嵌入到另一個web頁面中,以及如何更新您自己的可更新數據庫表小構件。
新聞熱點
疑難解答
圖片精選