高偉,郭瑾,劉德山,徐本強(qiáng)
在傳統(tǒng)的瀏覽器與服務(wù)器的交互方式中,當(dāng)用戶觸發(fā)一個HTTP請求到服務(wù)器,服務(wù)器對其進(jìn)行處理后再返回一個新的Web頁到瀏覽器,每當(dāng)服務(wù)器處理瀏覽器提交的請求時,用戶總是被強(qiáng)制進(jìn)入提交→等待→重新顯示模式,這不僅效率低,而且大大減弱了用戶體驗(yàn)。同時,刷新時造成的數(shù)據(jù)重復(fù)請求也加大了服務(wù)器的負(fù)擔(dān)。
Ajax提供與服務(wù)器異步通信的能力,可以在瀏覽器快速無刷新的顯示信息,它可以使得系統(tǒng)響應(yīng)更敏捷、交互性更強(qiáng)、用戶體驗(yàn)更豐富。
Ajax是于2005年由Jesse James Garrett 最先提出的[1]。Ajax(Asynchronous JavaScript and XML)自從產(chǎn)生以來,催生了一系列基于Web的新的服務(wù)方式,其核心是利用Ajax的異步交互,減輕服務(wù)器負(fù)擔(dān),提高應(yīng)用操作的執(zhí)行效率。異步是指客戶端的請求/響應(yīng)和用戶的動作是異步進(jìn)行的,客戶端在等待服務(wù)器響應(yīng)時不必阻塞用戶,用戶可以繼續(xù)進(jìn)行其他的行為。
Ajax使用XHTML和CSS標(biāo)準(zhǔn)化呈現(xiàn),使用DOM實(shí)現(xiàn)動態(tài)顯示和交互,使用XML和XSTL進(jìn)行數(shù)據(jù)交換與處理,使用XMLHttpRequest對象進(jìn)行異步數(shù)據(jù)讀取,使用JavaScript綁定和處理所有數(shù)據(jù)。
Ajax應(yīng)用程序在用戶和服務(wù)器之間引入了一個中間層:Ajax引擎,使用戶操作與服務(wù)器響應(yīng)異步化,改變了使用頁面重載的響應(yīng)方式。當(dāng)用戶提交請求時,使用JavaScript和XML立即跟新UI(User Inte-Face),并向服務(wù)器發(fā)出異步請求;當(dāng)請求返回時,使用JavaScript和CSS來相應(yīng)地更新UI。用戶端完全沒有被中斷的感覺。傳統(tǒng)的Web應(yīng)用交互模式是同步的,而基于Ajax技術(shù)的Web應(yīng)用交互模式是異步的,如圖1所示[1]。因此Ajax應(yīng)用與傳統(tǒng)的Web應(yīng)用的區(qū)別主要在三個方面:
(1)不刷新整個頁面,在頁面內(nèi)與服務(wù)器通信;
(2)使用異步方式與服務(wù)器通信,不需要打斷用戶的操作,具有更加迅速的響應(yīng)能力;
(3)應(yīng)用僅有少量頁面組成,大部分交互在頁面內(nèi)完成,不需要切換整個頁面。
圖1 兩種Web應(yīng)用模型交互模式的對比
由此可見,Ajax使得Web應(yīng)用更加動態(tài),并且提供了表現(xiàn)能力豐富的Ajax UI組件。
Ajax技術(shù)當(dāng)中,最核心的技術(shù)就是XMLHttpRequ-est對象,它是Ajax技術(shù)與眾不同的地方。Ajax的無刷新更新頁面的效果,就是由XMLHttpRequest對象實(shí)現(xiàn)的。XMLHttpRequest對象在IE5中首次出現(xiàn),負(fù)責(zé)在客戶端異步向服務(wù)器發(fā)送請求和處理響應(yīng)。XML-HttpRequest使用戶使用JavaScript向服務(wù)器提出請求并處理響應(yīng),同時不阻塞用戶[2]。
XMLHttpRequest對象提供了一系列屬性和方法來向服務(wù)器發(fā)送異步的Http請求。在服務(wù)器處理用戶請求的過程中,XMLHttpRequest監(jiān)聽服務(wù)器的狀態(tài),并根據(jù)這些狀態(tài)指示JavaScript做相應(yīng)的處理。當(dāng)服務(wù)器順利完成響應(yīng)用戶行為的動作、并將響應(yīng)數(shù)據(jù)返回時,XMLHttpRequest對象能夠回調(diào)響應(yīng)的處理函數(shù);通過XMLHttpRequest提供的response系列方法,可以將這些響應(yīng)數(shù)據(jù)由JavaScript操縱的DOM更新Web頁面內(nèi)容。
網(wǎng)絡(luò)答疑系統(tǒng)是基于J2EE和MVC開發(fā)模式,技術(shù)上采用Struts+Spring+Hibernate三層開發(fā)模式。
MVC設(shè)計(jì)模式由控制器(Controller)、模型(Model)、視圖(View)三部分組成[3]。模型表示應(yīng)用程序的業(yè)務(wù)邏輯,獲取業(yè)務(wù)數(shù)據(jù)并按照業(yè)務(wù)規(guī)則處理業(yè)務(wù)數(shù)據(jù),所有的業(yè)務(wù)操作都在該層,是應(yīng)用程序的核心。視圖是整個應(yīng)用程序的外在表現(xiàn),主要功能是模塊的顯示以及根據(jù)業(yè)務(wù)處理結(jié)果生成返回至客戶端的頁面??刂破髦饕δ苁菍⒛P秃鸵晥D聯(lián)系在一起,是一個分發(fā)器,不做任何數(shù)據(jù)處理。MVC模式實(shí)現(xiàn)了數(shù)據(jù)層、顯示層和業(yè)務(wù)層的分離,提高了系統(tǒng)的可維護(hù)性、可擴(kuò)展性和可重用性。
網(wǎng)絡(luò)答疑系統(tǒng)由五層組成,如圖2:
圖2 基于Struts、Spring和Hibernate的Web開發(fā)框架
這五層分別是:
客戶層:客戶端使用瀏覽器進(jìn)入系統(tǒng)訪問,與服務(wù)器端軟件進(jìn)行交互;
表示層即Web層:使用Struts框架,處理用戶的請求并做出相應(yīng)的響應(yīng),處理應(yīng)用程序的異常,在表單提交時進(jìn)行數(shù)據(jù)校驗(yàn),負(fù)責(zé)數(shù)據(jù)顯示和用戶交互;
業(yè)務(wù)邏輯層:使用Spring框架通過IoC(反轉(zhuǎn)控制)機(jī)制進(jìn)行業(yè)務(wù)邏輯的調(diào)用[4],包括:處理應(yīng)用程序的業(yè)務(wù)邏輯和業(yè)務(wù)校驗(yàn)、數(shù)據(jù)庫的事務(wù)管理、數(shù)據(jù)訪問層的連接管理等;
數(shù)據(jù)持久層:使用Hibernate框架從數(shù)據(jù)源中獲取數(shù)據(jù),實(shí)現(xiàn)數(shù)據(jù)的查詢、更新和刪除;
數(shù)據(jù)源層:數(shù)據(jù)庫系統(tǒng)負(fù)責(zé)管理、存儲、組織和分析系統(tǒng)的相關(guān)業(yè)務(wù)數(shù)據(jù)和用戶相關(guān)數(shù)據(jù)。
以上框架充分利用了三種開源框架各自的優(yōu)勢,Struts引入MVC模式實(shí)現(xiàn)了視圖、模型和控制互相分離,實(shí)現(xiàn)了表示邏輯和業(yè)務(wù)邏輯的解藕;Hibernate完成對象和關(guān)系數(shù)據(jù)庫之間的映射,并提供高效的數(shù)據(jù)存儲和獲取能力[5];Spring提供了IoC容器,完成持久訪問對象的注入和業(yè)務(wù)邏輯的事務(wù)管理,關(guān)聯(lián)Web層和數(shù)據(jù)持久層。采用多層體系結(jié)構(gòu),不僅實(shí)現(xiàn)了層間的松散耦合,提高了代碼的可重用性及開發(fā)效率,并且便于維護(hù)。
在網(wǎng)絡(luò)答疑系統(tǒng)中采用基于MVC模式的SSH三層框架結(jié)構(gòu),該結(jié)構(gòu)在服務(wù)器端提高了系統(tǒng)的靈活性,擴(kuò)展性大大加強(qiáng),便于調(diào)試,降低了維護(hù)成本。但客戶端只是采用傳統(tǒng)的瀏覽器與服務(wù)器的交互方式,這使得Struts在一些交互性強(qiáng)的頁面應(yīng)用不理想,導(dǎo)致刷新頁面頻繁,用戶等待時間長。在網(wǎng)絡(luò)答疑系統(tǒng)中,頁面交互頻繁,這樣不僅導(dǎo)致系統(tǒng)效率低,而且造成時間和網(wǎng)絡(luò)資源的浪費(fèi)。
基于Struts在客戶端的表現(xiàn)不足以及Ajax在客戶端的特點(diǎn),在網(wǎng)絡(luò)答疑系統(tǒng)中將Ajax和MVC模式相結(jié)合,充分發(fā)揮Ajax在客戶端的異步交互能力和MVC的可擴(kuò)展行。加入Ajax后,網(wǎng)絡(luò)答疑系統(tǒng)在原來的MVC三層架構(gòu)的基礎(chǔ)上形成了Ajax引擎、Struts層、Spring層和Hibernate層四層架構(gòu),客戶端表現(xiàn)出優(yōu)秀的動態(tài)顯示和交互能力。新的架構(gòu)見圖3:
圖3 Ajax在網(wǎng)絡(luò)答疑系統(tǒng)中的架構(gòu)圖
通過在網(wǎng)絡(luò)答疑系統(tǒng)的客戶端增加一個Ajax引擎,負(fù)責(zé)在客戶端和用戶之間交互,實(shí)現(xiàn)Ajax的功能。
當(dāng)用戶打開一個Web頁面時,就載入了Ajax引擎。Ajax引擎初始化后,就開始初始化XMLHttpRequest對象,捕捉用戶的行為,開始與用戶的交互。當(dāng)用戶的某些請求觸發(fā)Ajax時,,Ajax在后臺將用戶的數(shù)據(jù)異步請求送到Struts框架中的控制器ActionServlet處理,ActionServlet找到對應(yīng)的Action和ActionForm,在進(jìn)行Form驗(yàn)證,驗(yàn)證通過則調(diào)用Action的Execute方法。在方法體內(nèi),調(diào)用業(yè)務(wù)邏輯模塊,由Hibernate在“幕后”完成與數(shù)據(jù)庫的交互。即業(yè)務(wù)邏輯類里通過HQL語句操作業(yè)務(wù)對象,Hibernate把HQL轉(zhuǎn)換成SQL,通過O/R映射文件實(shí)現(xiàn)具體對數(shù)據(jù)源的操作,即穿過持久層映射到具體的數(shù)據(jù)庫表。ActionServlet接受Execute方法返回的ActionForward對象,轉(zhuǎn)發(fā)到ActionForward指定的另一個Action,Action層再將數(shù)據(jù)封裝成XML格式返回給Ajax引擎。Ajax引擎解析服務(wù)器傳遞過來的數(shù)據(jù),并借助于DOM、DHTML更新頁面,顯示數(shù)據(jù),完成一次請求響應(yīng)。具體的應(yīng)用流程框圖如圖4:
Ajax的所有動作都是在后臺進(jìn)行的,這樣就不會阻塞用戶的行為,也避免了用戶的等待時間。同時由于Ajax傳輸和接受的數(shù)據(jù)量相對都較小,因此頁面更新速度快,用戶有一種實(shí)時響應(yīng)的體驗(yàn)。另外,添加Ajax引擎后,使客戶端承擔(dān)部分服務(wù)器端邏輯,減輕了服務(wù)器的負(fù)擔(dān),同時從服務(wù)器端剝離了與業(yè)務(wù)無關(guān)的頁面交互邏輯,優(yōu)化了代碼結(jié)構(gòu)。
圖4 一次請求響應(yīng)的應(yīng)用流程框圖
在網(wǎng)絡(luò)答疑系統(tǒng)中,Ajax主要用于頁面交互和顯示。在答疑系統(tǒng)中,按照章節(jié)進(jìn)行問題的提出和答案的顯示,學(xué)生在提問之前可以先按章節(jié)進(jìn)行瀏覽查找問題是否已經(jīng)存在以及是否已經(jīng)給出答案,這樣按照章節(jié)逐層細(xì)化,呈現(xiàn)在用戶面前的是一個井井有條、層次感十分鮮明、簡單易用的網(wǎng)絡(luò)答疑系統(tǒng)軟件。因此,在該系統(tǒng)中使用了樹形目錄來實(shí)現(xiàn),并采用Ajax技術(shù)實(shí)現(xiàn)樹形目錄的動態(tài)顯示。
根據(jù)網(wǎng)絡(luò)答疑系統(tǒng)的多層架構(gòu)體系的構(gòu)造。在具體實(shí)現(xiàn)時,表示層專注于樹的外觀顯示,業(yè)務(wù)邏輯層完成處理樹的生成、變化。下面分別介紹:
當(dāng)點(diǎn)擊某節(jié)點(diǎn)前的“ + ”、“ - ”圖片時通過DIV 的style樣式的display 屬性控制子節(jié)點(diǎn)的展開和隱藏。部分代碼如下:
3.2.1 動態(tài)加載
如果一次性獲取完整的先序樹,構(gòu)造成XML提供給JavaScript解析,數(shù)據(jù)量越大,消耗的資源越多,客戶端響應(yīng)延遲時間就越長,因此對于大數(shù)據(jù)量的樹,采用動態(tài)加載方式,即每次單擊“+”圖片時,判斷是否已加載子節(jié)點(diǎn)數(shù)據(jù),如果未加載則通過Ajax的XMLHTTP組件XMLHttpRequest對象異步發(fā)送請求,連接服務(wù)器獲取節(jié)點(diǎn)數(shù)據(jù)。部分代碼如下:
3.2.2 樹形結(jié)構(gòu)的構(gòu)造
從數(shù)據(jù)庫中返回的是有序的先序樹,而XML是完整的樹型結(jié)構(gòu)文檔,所以將樹型數(shù)據(jù)構(gòu)造成預(yù)定義的XML格式,只需從根節(jié)點(diǎn)開始,遍歷一遍樹,即可將樹全部生成。部分代碼如下:
在初始化頁面時只讀出根節(jié)點(diǎn)的內(nèi)容并顯示,在用戶展開某一個根結(jié)點(diǎn)時,判斷是否已經(jīng)加載了子節(jié)點(diǎn)的數(shù)據(jù),如果未加載調(diào)用Ajax引擎,通過XMLHtt- pRequest對象異步發(fā)出請求,連接到服務(wù)器,通過GET方法異步連接到URL加載數(shù)據(jù)。這樣,每次只取一個節(jié)點(diǎn)的子節(jié)點(diǎn)序列,按XML格式封裝成樹的文檔結(jié)構(gòu),提供給JavaScript的dhtmlTreeObject.prototype.-
insertItem()解析并組織好HTML輸出節(jié)點(diǎn)。
由于使用了異步交互方式,在與服務(wù)器交互的同時用戶仍然可以繼續(xù)頁面的其它操作,并且每次只是讀取子節(jié)點(diǎn)的數(shù)據(jù),而不是加載所有的子節(jié)點(diǎn)和葉子節(jié)點(diǎn)的全部數(shù)據(jù),這樣,所取即所用的方式不會產(chǎn)生數(shù)據(jù)的冗余和浪費(fèi),減少了數(shù)據(jù)下載量,避免了更新頁面時重載全部內(nèi)容,縮短了用戶等待時間。
在網(wǎng)絡(luò)答疑系統(tǒng)中,采用了基于Ajax的Struts+
Spring+Hibernate的架構(gòu)模式。此框架的應(yīng)用一方面
減少了用戶交互過程中的等待時間,提高了系統(tǒng)的響應(yīng)速度,同時采用成熟的SSH框架,縮短開發(fā)時間,降低了開發(fā)成本,增強(qiáng)了系統(tǒng)的可維護(hù)性和可擴(kuò)展性。Ajax引擎的應(yīng)用彌補(bǔ)了SSH框架在客戶端的不足,實(shí)現(xiàn)了異步交互和動態(tài)刷新顯示的功能,也避免了刷新等待造成的時間和帶寬的浪費(fèi),提高了系統(tǒng)的資源利用率,比傳統(tǒng)的Web應(yīng)用模式具有更強(qiáng)的交互性。
[1]Garrett J J .Ajax: A new approach to web applications[EB/OL].http://www.adaptivepath.com .
[2]Ryan Asleson,Nathaniel T. Schutta. Foundation of Ajax[M]. Apress,Oct 2005.
[3]Husted T, Dumoulin C, Franciscus G, et al. Struts in action[M]. Amercia:Manning Publications Co,2003:1-581.
[4]Johnson R,Hoeller J,Arendsen A,et al. Spring - Java/J2EE application framework reference documentation[EB/OL].http://static.springframework.org/spring/docs/1.2.x/reference/index.html.
[5]King G.Hi bernatereference[EB/OL].http://www.hibernate.org/hib_docs/v3/reference/en/html/architecture.html.