在網(wǎng)絡(luò)需求越來越多的時代,傳統(tǒng)的Web1.0技術(shù)由于其同步交互方式,帶來了很大網(wǎng)絡(luò)流量以及很差的用戶體驗,以Wiki,google Map等為代表的Web2.0技術(shù)以及RIA的應(yīng)用極大地提高了網(wǎng)絡(luò)性能和用戶體驗,成為了Web應(yīng)用領(lǐng)域的主力軍。在實現(xiàn)高用戶體驗及時交互方面,有5種技術(shù)可供選擇:1)Flex和OpenLaszlo;2)IBM?WorkplaceTMManaged Client和IBM Lotus?Expeditor;3)Faces Client Com-ponents;4)Ajax;5)HTML[1],考慮到開發(fā)難度以及具體C2C交易平臺后臺系統(tǒng)的特點,選擇Ajax技術(shù)。Ajax綜合了以前DHTML技術(shù),通過XMLRequest出色地完成了異步交互功能,帶來了系統(tǒng)性能的很大提升。然而純Ajax代碼相當(dāng)復(fù)雜,開發(fā)和調(diào)試都比較麻煩,同時需要前端美工和后臺程序員很好的合作,才能構(gòu)建出好的Ajax應(yīng)用。幸運的是,ExtJS提供了很好的解決方案,程序員不需要精通DHTML就可以輕易地構(gòu)建一套高用戶體驗界面,同時ExtJS是基于JavaScript的,對Ajax有很好的支持。因而,后臺程序員就能脫離前臺美工來獨立構(gòu)建高用戶體驗的Web系統(tǒng)。
1Ajax技術(shù)與ExtJS框架概述1.1Ajax原理
作為DHTML技術(shù)的升級,Ajax大部分沿用了以前的老技術(shù),它是將一部分業(yè)務(wù)邏輯轉(zhuǎn)移到客戶端,使得客戶端不僅僅是個頁面,而且有強大的業(yè)務(wù)邏輯支撐著,一般是用JavaScript實現(xiàn)的,html與css負(fù)責(zé)界面的實現(xiàn)。從這方面講也類似于C/S結(jié)構(gòu),不過Ajax是盡可能的實現(xiàn)C/S結(jié)構(gòu)高交互能力效果的同時又保持B/S結(jié)構(gòu)的平臺無關(guān)性。
瀏覽器在執(zhí)行任務(wù)時會自動裝載Ajax引擎[2]。具體過程:瀏覽器發(fā)送請求到服務(wù)器,服務(wù)器響應(yīng)請求,把頁面數(shù)據(jù)(包括html,js,css文件)發(fā)送到瀏覽器,瀏覽器解析成網(wǎng)頁,可以將其看作是一個小型的客戶端程序,用戶可以像使用桌面應(yīng)用程序一樣來操作頁面。當(dāng)用戶點擊頁面上某一按鈕或其他,瀏覽器端便會相應(yīng)產(chǎn)生一個事件,瀏覽器端控制器感應(yīng)該事件,而調(diào)用相應(yīng)的Model來實現(xiàn)相應(yīng)的業(yè)務(wù)邏輯。Model利用XMLHTTPReader發(fā)送請求到服務(wù)器,服務(wù)器響應(yīng)請求,回復(fù)相應(yīng)的數(shù)據(jù)到瀏覽器端,然后XMLHttpReader回調(diào)callback(),接收并解析數(shù)據(jù)。一般回復(fù)的數(shù)據(jù)為txt,json或xml。最后Model利用DOM(Document Object Model,文檔對象模型)找到或創(chuàng)建頁面上相應(yīng)的元素,將解析后的數(shù)據(jù)加載到相應(yīng)的元素上,View將數(shù)據(jù)顯示在頁面,圖1是Ajax的調(diào)用示意圖。
圖1 Ajax調(diào)用示意圖Fig.1Schematic diagram of calling Ajax
基于Ajax的客戶端其實也是一個類似于服務(wù)器端的MVC實現(xiàn)。與傳統(tǒng)Web1.0技術(shù)相比,可以看出Ajax摒棄了整個頁面刷新式的交互,而是采用異步事件處理的方式來請求服務(wù)器端的關(guān)鍵數(shù)據(jù)(即不帶html標(biāo)記的數(shù)據(jù)),擁有自身的業(yè)務(wù)邏輯,從而大大減輕網(wǎng)絡(luò)壓力和服務(wù)器的壓力。
ExtJS發(fā)源于YUI,最先由Jack Slocum開發(fā),是采用OOP設(shè)計思想建立類庫與后臺語言無關(guān)的JavaScript框架[3],它將OOP發(fā)揮到了極致。然而ExtJS不僅僅是個JavaScript框架,它可以獨立于其他JavaScript框架通過Adapter(適配器)[4]。對于后臺程序員而言,不需要很深的網(wǎng)頁開發(fā)功底,就可以很快地開發(fā)出用戶體驗很高的類似桌面應(yīng)用的界面,一方面減少了與美工的交流,自己來開發(fā)客戶端界面,另一方面開發(fā)出來的界面交互能力很強,能夠很好地與后端服務(wù)器結(jié)合。
ExtJS提供了Ext.ViewPort視圖類,它可以根據(jù)layout配置,實現(xiàn)不同的布局風(fēng)格。在開發(fā)三農(nóng)商城后臺管理系統(tǒng)時,主界面采取border(邊界)布局方式,整體布局見圖2。它根據(jù)Ext.layout.BorderLayout.Region類定義的東西南北中5個區(qū)域來布局每一個區(qū)域,每個區(qū)域為一個panel面板類的實例。同時ViewPort會自動充斥整個瀏覽器。Ext提供了Ext.onReady(fn)方法,在頁面裝載完畢后,自動運行。與Window.onLoad()不同的是,Ext.onReady(fn)是在頁面裝載完畢后,而不是等到所有的圖片和flash等裝載完畢后執(zhí)行,這樣相對于傳統(tǒng)的Window.onLoad(),有更高的響應(yīng)速度。
圖2 整體布局效果圖Fig.2The overall layout diagram
代碼如下:
Ext.onReady(function(){var mainViewPort=new Ext.ViewPort({renderTo:Ext.getBody(),layout:“border”,items:[{xtype:"panel",title:"頂部標(biāo)題欄",region:"north"},{/*略*/},{/*略*/},{/*略*/},{/*略*/},{/*略*/}]})
});
Ext提供了對樹的支持,包括TreePanel樹面板,TreeNode樹節(jié)點,TreeLoader樹加載器。利用樹,可以很好的表示數(shù)據(jù)的層次結(jié)構(gòu)。如創(chuàng)建動態(tài)類別樹結(jié)構(gòu)。通過TreePanel創(chuàng)建一個面板,每一個類別即是一個節(jié)點,用TreeLoader異步請求服務(wù)器,得到數(shù)據(jù),然后解析顯示到頁面上。一般數(shù)據(jù)傳輸?shù)母袷接衳ml和Json兩種,由于Json的數(shù)據(jù)量比較小,而且是JavaScript固有的對象支持格式,大多都使用Json的方式。下面以基于J2EE的三農(nóng)商城開發(fā)中省市縣動態(tài)樹為例介紹動態(tài)樹的實現(xiàn)技術(shù),圖3是省市縣動態(tài)樹效果圖。
圖3 Tree效果圖Fig.3Tree diagram
基于J2EE的省市縣動態(tài)樹客戶端開發(fā)代碼如下:Ext.onReady(function(){
var loader=new Ext.tree.TreeLoader({url:"manage/categoryMng!getTree"http://請求的地址});
//在節(jié)點內(nèi)容加載前執(zhí)行
loader.on("beforeload",function(loader,node){loader.baseParams.id=node.id;//向服務(wù)器端傳遞參數(shù)});
var areaTreePanel=new Ext.tree.TreePanel({id:"all",title:"類別",renderTo:Ext.getBody(),root:"all",loader:loader});
});
在服務(wù)器端,采用Struts2.1表示層框架,為了使其能方便地支持Json,使用json-plugin插件。服務(wù)器端Action代碼如下:
public class CategoryMng extends ActionSupport
{@Resource CategoryService categoryServiceBean;
private List<Node>nodes=new ArrayList<Node>();
public String getTree()throws Exception
{String id=ServletActionContext.getRequest().getParameter("id");
Set<Category>categorys=categoryServiceBean.get(id).getChildren();
//通過DAO獲取子類別
nodes=categoryServiceBean.toNodes(categorys);//轉(zhuǎn)化為節(jié)點類
return super.SUCCESS;
}
public List<Node>getNodes()
{return nodes;}
}
節(jié)點類代碼如下:
public class Node
{public String id;//序號
public String url;//鏈接地址
public boolean leaf;//是否是葉子節(jié)點
/*set和get方法略*/
}
struts.xml文件配置如下:
<packagename="manage"namespace="/manage"extends="json-default">
<action name="categoryMng"class="com.hncu.web.action.CategoryMng">
<result type="json">
<param name="root">nodes</param>
</result>
</action>
</package>
在傳統(tǒng)的DHTML技術(shù)中,網(wǎng)頁動態(tài)加載一般都是通過iframe嵌套加入網(wǎng)頁中,這樣每次加載都要重新引入js和css文件,嚴(yán)重情況下,一個頁面層層迭代嵌入了6、7個iframe,極大地增加了網(wǎng)絡(luò)壓力和客戶端CPU開銷。ExtJS提供了panel動態(tài)加載網(wǎng)頁的功能,可以在不重新加載js和css文件的情況下,將html嵌入指定的div中。在ExtJS3.2中,改進了動態(tài)內(nèi)嵌入網(wǎng)頁的功能,增加了對JavaScript代碼的支持,將JavaScript作為腳本解釋型語言的特性發(fā)揮到極致。
Ext.Window動態(tài)加載實現(xiàn)代碼如下:
var win=Ext.Window({/*略*/})
win.load({url:"manage/productList.action",//請求的地址
params:{//帶入?yún)?shù)
categoryId:1,pageSize:10
},script:true
});
在B/S結(jié)構(gòu)中,瀏覽器與服務(wù)器之間的交互方式是單方面的,即瀏覽器主動請求服務(wù)器,然后服務(wù)器與瀏覽器之間建立TCP/IP連接,并且兩者之間的會話是無狀態(tài)的。盡管真正意義上的雙向交互是不可能的,但是可以利用Ajax技術(shù)讓瀏覽器定時自動向服務(wù)器發(fā)出請求,達(dá)到實時更新的效果。下面以三農(nóng)商城系統(tǒng)消息實時提醒為例來討論實時更新的實現(xiàn)。
客戶端代碼如下:
var htmlContent;
function ajaxInterval()
{Ext.Ajax.request({url:"updateAction",//請求的地址
method:'GET',success:function(response)
{//利用JSON進行編碼,返回JavaScript的原生類類型
var obj=Ext.util.JSON.decode(response.responseText);
for(var i=0;i<o(jì)bj.length();i++)
{/*把obj組裝成html代碼賦值給htmlContent*/}
}
});
}//設(shè)置定時器
window.setInterval("ajaxRequest()",3000);
/**將htmlContent按照表現(xiàn)邏輯顯示到頁面上**/
系統(tǒng)通過window.setInterval()函數(shù)來定時執(zhí)行ajaxRequest()方法,從而動態(tài)請求服務(wù)器,然后將返回的數(shù)據(jù)用JSON進行解析后,顯示到頁面,從而達(dá)到實時更新消息的效果。服務(wù)器端代碼JSON組裝代碼參考2.2。
為了避免用戶在數(shù)據(jù)輸入時遇到斷電、網(wǎng)絡(luò)中斷等意外時造成數(shù)據(jù)丟失,減低工作效率等問題,因而需要采用自動保存機制。自動保存機制主要有兩種方法,一種是及時保存到服務(wù)器,另一種是把數(shù)據(jù)及時保存到本地機器。第一種是定時把數(shù)據(jù)發(fā)送到服務(wù)器,讓服務(wù)器持久化到數(shù)據(jù)庫中,顯然這種方式代價很大,增加了Web服務(wù)器和數(shù)據(jù)庫服務(wù)器的壓力;第二種是先保存到本地機器cookie中,待故障恢復(fù)后自動發(fā)送到服務(wù)器持久化。
TextArea狀態(tài)保存代碼實現(xiàn)如下[5]:
StatefulTextArea=Ext.extend(Ext.form.TextArea,{stateEvents:['change'],//設(shè)置狀態(tài)監(jiān)聽事件
getState:function(){return{text:this.value//設(shè)置保存的數(shù)據(jù)為TextArea的值}},
applyState:function(state){this.setValue(state.text);//設(shè)置狀態(tài)應(yīng)用事件}
});
//設(shè)置狀態(tài)管理器提供者為Cookie
Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
expires:new Date(new Date().getTime()+(1000*60*60*24*30))//保存一個月}));
在ExtJS3.2中,單extjs-all.js文件就有600多K,按1Mb/s的網(wǎng)速算,單加載這個文件就要耗費大約5 s,使得響應(yīng)時間增加了很多。其實ExtJS中的js文件是可以定制的,可以根據(jù)自己的需要來導(dǎo)入關(guān)聯(lián)的js文件,而沒必要一次性導(dǎo)入所有的庫。另一方面,即使要用到某個js文件,如果不是馬上要用到的話,也沒必要一開始就加載進去,可以采用延遲加載的原則,用到時再加載。
造成瀏覽器與服務(wù)器之間傳輸量大的很大一部分原因是由于傳輸數(shù)據(jù)中存在大量的空格等無用字符,因此,采用GZIP做為http壓縮工具,對靜態(tài)文件html,javaScript,css,Text以及動態(tài)JSP,Servlet輸出的網(wǎng)頁進行壓縮,從而減少網(wǎng)絡(luò)流量。tomcat容器下GZIP壓縮配置參考文獻[6]。
緩存技術(shù)已經(jīng)應(yīng)用到計算機領(lǐng)域的各個方面,在J2EE方面,數(shù)據(jù)庫,業(yè)務(wù)邏輯層,表現(xiàn)層都可以設(shè)置緩存。它通過對大量訪問同一種資源進行保存,而減少不必要的服務(wù)器負(fù)載壓力,達(dá)到提高效率的目的。頁面緩存是通過html提供的meta標(biāo)簽的http-equiv屬性來實現(xiàn)。包括:
1)<meta http-equiv="Expires"content="">可以用于設(shè)定網(wǎng)頁到期時間,一旦過期則必須到服務(wù)器上重新調(diào)用,必須使用GMT時間格式;
2)<meta http-equiv="Pragma"content="no-cache|nostore|max-age|max-state|min-fresh|onif-cached">是用于設(shè)定禁止瀏覽器從本地機緩存中調(diào)閱頁面內(nèi)容,設(shè)定后一旦離開網(wǎng)頁就無法從Cache中再調(diào)出;
3)<meta http-equiv="cache-contro"content="no-cache|no-store|max-age|max-state|min-fresh|onif-cached">指定和響應(yīng)遵循的緩存機制,它不會影響另一個消息處理的緩存過程。
在頁面緩存方面,OSCache給我們提供了一個良好的框架,通過這個工具,可以自由的選擇緩存區(qū)域(硬盤,內(nèi)存),緩存范圍(頁面級緩存和部分頁面內(nèi)容緩存)。同時也提供了豐富的標(biāo)簽,方便了JSP的配置。詳細(xì)配置參考文獻[7]。
Ajax作為Web2.0的核心技術(shù)之一,帶來了Web用戶體驗革命性的改變。ExtJS作為Ajax的客戶端UI框架,很大程度上減少了系統(tǒng)開發(fā)成本,同時又保證了系統(tǒng)的美化以及頁面響應(yīng)速度。利用Ajax+ExtJS組合,有效避開了傳統(tǒng)B/S結(jié)構(gòu)用戶體驗差的特點,又具有了C/S結(jié)構(gòu)的強交互能力,同時還具有很好的可移植性和可維護性。作為RIA應(yīng)用的新生兒,ExtJS將走得更遠(yuǎn)。
[1]宋轉(zhuǎn)玲,劉海行,代亮,等.基于ExtJS開發(fā)的海洋科學(xué)數(shù)據(jù)共享平臺[J].海洋科學(xué),2010,34(2):4-9.SONG Zhuan-ling,LIU Hai-xing,DAI Liang,et al.Qingdao oceanic data service system based on ExtJS[J].Marine Sciences,2010,34(2):4-9.
[2]鄭玲,蒲強,劉曉建.基于AJAX技術(shù)構(gòu)建汽輪機組遠(yuǎn)程故障監(jiān)測系統(tǒng)的設(shè)計與研究[J].中國電力教育,2008,(S2):353-355.ZHENG Ling,PU Qiang,LIU Xiao-jian.Design and research of the turbine remote fault monitoring system based on AJAX[J].China Electric Power Educationm,2008,(S2):353-355.[3]雷鐳,陳俊.基于ExtJS及Pushlet實現(xiàn)Web及時交流[J].軟件導(dǎo)刊,2010,9(2):118-120.LEI Lei,CHEN Jun.Implementation of Web communication by ExtJS and pushlet[J].Software Guide,2010,9(2):118-120.
[4]Frederick S,Ramsay C,Steve Cutter Blades.Learning ExtJS[M].Packt Publishing Ltd.,2008:10-21.
[5]ExtJS3.2 document[EB/OL].(2010-4-12)[2010-10-1].http://dev.sencha.com/deploy/dev/docs/.
[6]Apache Tomcat6.0 document[EB/OL].(2010-3-24)[2010-10-1].http://fangrn.javaeye.com/blog/623339.
[7]Opensymphony[EB/OL].(2009-3-6)[2011-3-1].http://www.opensymphony.com/oscache/wiki/CacheFilter.html.