面向Java程序員的AJAX_第1頁
面向Java程序員的AJAX_第2頁
面向Java程序員的AJAX_第3頁
面向Java程序員的AJAX_第4頁
面向Java程序員的AJAX_第5頁
已閱讀5頁,還剩29頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

面向Java程序員的AJAX面向Java程序員的AJAX面向Java程序員的AJAX面向Java程序員的AJAX編制僅供參考審核批準生效日期地址:電話:傳真:郵編:面向

Java開發人員的Ajax:

構建動態的Java應用程序Ajax為更好的Web應用程序鋪平了道路打印本頁將此頁作為電子郵件發送討論樣例代碼級別:中級PhilipMcCarthy

(C:\Users\Administrator\Desktop\封面(2)\subject=構建動態的Java應用程序),軟件開發顧問,獨立咨詢顧問2005年10月20日在Web應用程序開發中,頁面重載循環是最大的一個使用障礙,對于Java?開發人員來說也是一個嚴峻的挑戰。在這個系列中,作者PhilipMcCarthy介紹了一種創建動態應用程序體驗的開創性方式。Ajax(異步JavaScript和XML)是一種編程技術,它允許為基于Java的Web應用程序把Java技術、XML和JavaScript組合起來,從而打破頁面重載的范式。Ajax(即異步JavaScript和XML)是一種Web應用程序開發的手段,它采用客戶端腳本與Web服務器交換數據。所以,不必采用會中斷交互的完整頁面刷新,就可以動態地更新Web頁面。使用Ajax,可以創建更加豐富、更加動態的Web應用程序用戶界面,其即時性與可用性甚至能夠接近本機桌面應用程序。Ajax不是一項技術,而更像是一個

模式

——一種識別和描述有用的設計技術的方式。Ajax是新穎的,因為許多開發人員才剛剛開始知道它,但是所有實現Ajax應用程序的組件都已經存在若干年了。它目前受到重視是因為在2004和2005年出現了一些基于Ajax技術的非常棒的動態WebUI,最著名的就是Google的GMail和Maps應用程序,以及照片共享站點Flickr。這些用戶界面具有足夠的開創性,有些開發人員稱之為“Web”,因此對Ajax應用程序的興趣飛速上升。在這個系列中,我將提供使用Ajax開發應用程序需要的全部工具。在第一篇文章中,我將解釋Ajax背后的概念,演示為基于Java的Web應用程序創建Ajax界面的基本步驟。我將使用代碼示例演示讓Ajax應用程序如此動態的服務器端Java代碼和客戶端JavaScript。最后,我將指出Ajax方式的一些不足,以及在創建Ajax應用程序時應當考慮的一些更廣的可用性和訪問性問題。更好的購物車可以用Ajax增強傳統的Web應用程序,通過消除頁面裝入從而簡化交互。為了演示這一點,我采用一個簡單的購物車示例,在向里面添加項目時,它會動態更新。這項技術如果整合到在線商店,那么用戶可以持續地瀏覽和向購物車中添加項目,而不必在每次點擊之后都等候完整的頁面更新。雖然這篇文章中的有些代碼特定于購物車示例,但是演示的技術可以應用于任何Ajax應用程序。清單1顯示了購物車示例使用的有關HTML代碼,整篇文章中都會使用這個HTML。

清單1.購物車示例的有關片斷<!--Tableofproductsfromstore'scatalog,onerowperitem--><th>Name</th><th>Description</th><th>Price</th><th></th>...<tr><!--Itemdetails--><td>Hat</td><td>Stylishbowlerhat</td><td>$</td><td><!--ClickbuttontoadditemtocartviaAjaxrequest--><buttononclick="addToCart('hat001')">AddtoCart</button></td></tr>...<!--Representationofshoppingcart,updatedasynchronously--><ulid="cart-contents"><!--List-itemswillbeaddedhereforeachiteminthecart--></ul><!--Totalcostofitemsincartdisplayedinsidespanelement-->Totalcost:<spanid="total">$</span>

回頁首Ajax往返過程Ajax交互開始于叫作

XMLHttpRequest

的JavaScript對象。顧名思義,它允許客戶端腳本執行HTTP請求,并解析XML服務器響應。Ajax往返過程的第一步是創建

XMLHttpRequest

的實例。在XMLHttpRequest

對象上設置請求使用的HTTP方法(GET

POST)以及目標URL?,F在,您還記得Ajax的第一個

a

是代表

異步(asynchronous)

嗎在發送HTTP請求時,不想讓瀏覽器掛著等候服務器響應。相反,您想讓瀏覽器繼續對用戶與頁面的交互進行響應,并在服務器響應到達時再進行處理。為了實現這個要求,可以在

XMLHttpRequest

上注冊一個回調函數,然后異步地分派

XMLHttpRequest。然后控制就會返回瀏覽器,當服務器響應到達時,會調用回調函數。在JavaWeb服務器上,請求同其他

HttpServletRequest

一樣到達。在解析了請求參數之后,servlet調用必要的應用程序邏輯,把響應序列化成XML,并把XML寫入

HttpServletResponse?;氐娇蛻舳藭r,現在調用注冊在

XMLHttpRequest

上的回調函數,處理服務器返回的XML文檔。最后,根據服務器返回的數據,用JavaScript操縱頁面的HTMLDOM,把用戶界面更新。圖1是Ajax往返過程的順序圖。

圖1.Ajax往返過程

現在您對Ajax往返過程有了一個高層面的認識。下面我將放大其中的每一步驟,進行更詳細的觀察。如果過程中迷了路,請回頭看圖1——由于Ajax方式的異步性質,所以順序并非十分簡單。

回頁首分派XMLHttpRequest我將從Ajax序列的起點開始:創建和分派來自瀏覽器的

XMLHttpRequest。不幸的是,不同的瀏覽器創建

XMLHttpRequest

的方法各不相同。清單2的JavaScript函數消除了這些依賴于瀏覽器的技巧,它可以檢測當前瀏覽器要使用的正確方式,并返回一個可以使用的

XMLHttpRequest。最好是把它當作輔助代碼:只要把它拷貝到JavaScript庫,并在需要

XMLHttpRequest

的時候使用它就可以了。

清單2.創建跨瀏覽器的XMLHttpRequest/**ReturnsanewXMLHttpRequestobject,orfalseifthisbrowser*doesn'tsupportit*/functionnewXMLHttpRequest(){varxmlreq=false;if{分派AddtoCartXMLHttpRequest/**Addsanitem,identifiedbyitsproductcode,totheshoppingcart*itemCode-productcodeoftheitemtoadd.*/functionaddToCart(itemCode){("POST","",true);("action=add&item="+itemCode);}這就是建立Ajax往返過程的第一部分,即創建和分派來自客戶機的HTTP請求。接下來是用來處理請求的Javaservlet代碼。

回頁首servlet請求處理用servlet處理

XMLHttpRequest,與處理普通的瀏覽器HTTP請求一樣??梢杂?/p>

()

得到在POST請求體中發送的表單編碼數據。Ajax請求被放進與來自應用程序的常規Web請求一樣的

HttpSession

中。對于示例購物車場景來說,這很有用,因為這讓我可以把購物車狀態封裝在JavaBean中,并在請求之間在會話中維持這個狀態。清單4是處理Ajax請求、更新購物車的簡單servlet的一部分。Cart

bean是從用戶會話中獲得的,并根據請求參數更新它的狀態。然后

Cart

被序列化成XML,XML又被寫入

ServletResponse。重要的是把響應的內容類型設置為

application/xml,否則

XMLHttpRequest

不會把響應內容解析成XMLDOM。

清單4.處理Ajax請求的servlet代碼publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)throws{Cartcart=getCartFromSession(req);Stringaction=("action");Stringitem=("item");if((action!=null)&&(item!=null)){quals(action)){(item);}elseif("remove".equals(action)){(item);}}("application/xml");().write(cartXml);}清單5顯示了

()

方法生成的示例XML。它很簡單。請注意

cart

元素的

generated

屬性,它是

()

生成的一個時間戳。

清單5.Cart對象的XML序列化示例

<xmlversion=""><cartgenerated=""total="$"><itemcode="hat001"><name>Hat</name><quantity>2</quantity></item><itemcode="cha001"><name>Chair</name><quantity>1</quantity></item><itemcode="dog001"><name>Dog</name><quantity>1</quantity></item></cart>如果查看應用程序源代碼(可以從

下載

一節得到)中的,可以看到生成XML的方式只是把字符串添加在一起。雖然對這個示例來說足夠了,但是對于從Java代碼生成XML來說則是最差的方式。我將在這個系列的下一期中介紹一些更好的方式?,F在您已經知道了

CartServlet

響應

XMLHttpRequest

的方式。下一件事就是返回客戶端,查看如何用XML響應更新頁面狀態。

回頁首用JavaScript進行響應處理XMLHttpRequest

readyState

屬性是一個數值,它指出請求生命周期的狀態。它從0(代表“未初始化”)變化到4(代表“完成”)。每次

readyState

變化時,readystatechange

事件就觸發,由onreadystatechange

屬性指定的事件處理函數就被調用。在

清單3

中已經看到了如何調用

getReadyStateHandler()

函數創建事件處理函數。然后把這個事件處理函數分配給

onreadystatechange

屬性。getReadyStateHandler()

利用了這樣一個事實:函數是JavaScript中的一級對象。這意味著函數可以是其他函數的參數,也可以創建和返回其他函數。getReadyStateHandler()

的工作是返回一個函數,檢查

XMLHttpRequest

是否已經完成,并把XML響應傳遞給調用者指定的事件處理函數。清單6是

getReadyStateHandler()

的代碼。

清單6.getReadyStateHandler()函數/**ReturnsafunctionthatwaitsforthespecifiedXMLHttpRequest*tocomplete,thenpassesitsXMLresponsetothegivenhandlerfunction.*req-TheXMLHttpRequestwhosestateischanging*responseXmlHandler-FunctiontopasstheXMLresponseto*/functiongetReadyStateHandler(req,responseXmlHandler){更新頁面,反映購物車的XML文檔functionupdateCart(cartXML){varquantity=("quantity")[0].;nnerHTML=("total");}到此,整個Ajax往返過程完成了,但是您可能想讓Web應用程序運行一下查看實際效果(請參閱

下載

一節)。這個示例非常簡單,有很多需要改進之處。例如,我包含了從購物車中清除項目的服務器端代碼,但是無法從UI訪問它。作為一個好的練習,請試著在應用程序現有的JavaScript代碼之上構建出能夠實現這個功能的代碼。

回頁首使用Ajax的挑戰就像任何技術一樣,使用Ajax也有許多出錯的可能性。我目前在這里討論的問題還缺乏容易的解決方案,但是會隨著Ajax的成熟而改進。隨著開發人員社區增加開發Ajax應用程序的經驗,將會記錄下最佳實踐和指南。XMLHttpRequest的可用性Ajax開發人員面臨的一個最大問題是:在沒有

XMLHttpRequest

可用時該如何響應雖然主要的現代瀏覽器都支持

XMLHttpRequest,但仍然有少數用戶的瀏覽器不支持,或者瀏覽器的安全設置阻止使用XMLHttpRequest。如果開發的Web應用程序要部署在企業內部網,那么可能擁有指定支持哪種瀏覽器的權力,從而可以認為

XMLHttpRequest

總能使用。但是,如果要部署在公共Web上,那么就必須當心,如果假設

XMLHttpRequest

可用,那么就可能會阻止那些使用舊的瀏覽器、殘疾人專用瀏覽器和手持設備上的輕量級瀏覽器的用戶使用您的應用程序。所以,您應當努力讓應用程序“平穩降級”,在沒有

XMLHttpRequest

支持的瀏覽器中也能夠工作。在購物車的示例中,把應用程序降級的最好方式可能是讓AddtoCart按鈕執行一個常規的表單提交,刷新頁面來反映購物車更新后的狀態。Ajax的行為應當在頁面裝入的時候就通過JavaScript添加到頁面,只有在

XMLHttpRequest

可用時才把JavaScript事件處理函數附加到每個AddtoCart按鈕。另一種方式是在用戶登錄時檢測

XMLHttpRequest

是否可用,然后相應地提供應用程序的Ajax版本或基于表單的普通版本??捎眯钥紤]關于Ajax應用程序的某些可用性問題比較普遍。例如,讓用戶知道他們的輸入已經注冊了可能是重要的,因為沙漏光標和spinning瀏覽器的常用反饋機制“throbber”對

XMLHttpRequest

不適用。一種技術是用“Nowupdating...”類型的信息替換Submit按鈕,這樣用戶在等候響應期間就不會反復單擊按鈕了。另一個問題是,用戶可能沒有注意到他們正在查看的頁面的某一部分已經更新了??梢允褂貌煌目梢暭夹g,把用戶的眼球帶到頁面的更新區域,從而緩解這個問題。由Ajax更新頁面造成的其他問題還包括:“破壞了”瀏覽器的后退按鈕,地址欄中的URL也無法反映頁面的整個狀態,妨礙了設置書簽。請參閱

參考資料

一節,獲得專門解決Ajax應用程序可用性問題的文章。服務器負載用Ajax實現代替普通的基于表單的UI,會大大提高對服務器發出的請求數量。例如,一個普通的GoogleWeb搜索對服務器只有一個請求,是在用戶提交搜索表單時出現的。而GoogleSuggest試圖自動完成搜索術語,它要在用戶輸入時向服務器發送多個請求。在開發Ajax應用程序時,要注意將要發送給服務器的請求數量以及由此造成的服務器負荷。降低服務器負載的辦法是,在客戶機上對請求進行緩沖并且緩存服務器響應(如果可能的話)。還應該嘗試將AjaxWeb應用程序設計為在客戶機上執行盡可能多的邏輯,而不必聯絡服務器。處理異步非常重要的是,要理解無法保證

XMLHttpRequest

會按照分派它們的順序完成。實際上,應當假設它們不會按順序完成,并且在設計應用程序時把這一點記在心上。在購物車的示例中,使用最后更新的時間戳來確保新的購物車數據不會被舊的數據覆蓋(請參閱

清單7)。這個非?;镜姆绞娇梢杂糜谫徫镘噲鼍?,但是可能不適合其他場景。所以在設計時請考慮如何處理異步的服務器響應。

回頁首結束語現在您對Ajax的基本原則應當有了很好的理解,對參與Ajax交互的客戶端和服務器端組件也應當有了初步的知識。這些是基于Java的AjaxWeb應用程序的構造塊。另外,您應當理解了伴隨Ajax方式的一些高級設計問題。創建成功的Ajax應用程序要求整體考慮,從UI設計到JavaScript設計,再到服務器端架構;但是您現在應當已經武裝了考慮其他這些方面所需要的核心Ajax知識。如果使用這里演示的技術編寫大型Ajax應用程序的復雜性讓您覺得恐慌,那么有好消息給您。由于Struts、Spring和Hibernate這類框架的發展把Web應用程序開發從底層ServletAPI和JDBC的細節中抽象出來,所以正在出現簡化Ajax開發的工具包。其中有些只側重于客戶端,提供了向頁面添加可視效果的簡便方式,或者簡化了對

XMLHttpRequest

的使用。有些則走得更遠,提供了從服務器端代碼自動生成Ajax接口的方式。這些框架替您完成了繁重的任務,所以您可以采用更高級的方式進行Ajax開發。我在這個系列中將研究其中的一些。Ajax社區正在快速前進,所以會有大量有價值的信息涌現。在閱讀這個系列的下一期之前,我建議您參考

參考資料

一節中列出的文章,特別是如果您是剛接觸Ajax或客戶端開發的話。您還應當花些時間研究示例源代碼并考慮一些增強它的方式。在這個系列的下一篇文章中,我將深入討論

XMLHttpRequest

API,并推薦一些從JavaBean方便地創建XML的方式。我還將介紹替代XML進行Ajax數據傳遞的方式,例如JSON(JavaScriptObjectNotation)輕量級數據交換格式。

回頁首下載描述名字大小下載方法Samplecode8KBHTTP關于下載方法的信息參考資料學習您可以參閱本文在developerWorks全球站點上的

英文原文?!癇eyondtheDOM”(DetheElza,developerWorks,2005年5月):進行XML文檔訪問的有用的JavaScript技術。“AJAX及使用E4X編寫Web服務腳本,第1部分”(PaulFremantle和AnthonyElder,developerWorks,2005年4月):用Ajax在支持E4XJavaScript擴展的瀏覽器中進行SOAP調用?!癆jax:ANewApproachtoWebApplications”(JesseJamesGarrett,AdaptivePath,2005年2月):介紹Ajax起源的短文。TheJavaBluePrintsSolutionsCatalog:介紹了Ajax在幾個常見Web應用程序場景中的應用。:包含多項改進Ajax應用程序的UI技術。XMLHttpRequestUsabilityGuidelines:對使用Ajax提高用戶體驗的建議。AjaxMistakes:Ajax應用程序應當避免的可用性問題。Java技術專區:在這里可以找到關于Java編程的各個方面的文章。

獲得產品和技術MozillaFirefox:DOMInspector和JavaScriptDebugger擴展消除了許多Ajax開發的痛苦。

討論參與論壇討論。developerWorksblogs:加入developerWorks社區。面向Java開發人員的Ajax:

Ajax的Java對象序列化在Ajax應用程序中序列化數據的五種途徑級別:中級PhilipMcCarthy

(C:\Users\Administrator\Desktop\封面(2)\subject=Ajax的Java對象序列化),軟件開發顧問,獨立顧問2005年10月24日如果您正在使用異步JavaScript和XML(Ajax)進行Java?Web開發,那么您最關心的問題可能就是把數據從服務器傳遞給客戶機。在

面向Java開發人員的Ajax

系列的第二篇文章中,PhilipMcCarthy介紹了Java對象序列化的五種方式,并提供了選擇最適合應用程序的數據格式和技術所需要的全部信息。在這個系列的

第一篇文章

中,我介紹了Ajax的構造塊:如何用JavaScript

XMLHttpRequest

對象從Web頁面向服務器發送異步請求。如何用Javaservlet處理和響應請求(向客戶機返回XML文檔)。如何在客戶端用響應文檔更新頁面視圖。這一次,我將繼續討論Ajax開發的基礎知識,但是將側重于許多JavaWeb開發人員最關心的問題:為客戶機生成數據。多數Java開發人員已經把模型-視圖-控制器(MVC)模式應用在他們的Web應用程序上。在傳統的Web應用程序中,視圖組件由JSP或者其他表示技術(例如Velocity模板)構成。這些表示組件動態地生成全新的HTML頁面,替代用戶以前正在查看的頁面,從而更新用戶界面。但是,在JavaWeb應用程序使用AjaxUI的情況下,基于從

XMLHttpRequest

的響應接收到的數據,JavaScript客戶端代碼對于更新用戶看到的內容負有最終責任。從服務器的角度來看,視圖成為它響應客戶機請求而發送的數據表示。這篇文章側重于可以用來生成Java對象以數據為中心的視圖的技術。我將演示可以把JavaBeans變成XML文檔的各種方法,并且討論每種方法的優劣。您將看到為什么XML并不總是最好的途徑:對于簡單的Ajax請求來說,傳輸純文本更好。最后,我將介紹JavaScript對象標注(JSON)。JSON允許數據以序列化的JavaScript對象圖的形式傳輸,在客戶端代碼中處理序列化的JavaScript對象圖極為容易。關于示例我將使用一個示例應用程序和幾個用例來演示這里討論的技術特性和技術。圖1顯示的極為簡單的數據模型可以表示示例用例。這個模型代表在線商店中的顧客帳戶。顧客擁有以前訂單的集合,每個訂單包含幾個商品。

圖1.簡單的對象模型

雖然

XMLHttpRequest

對于發送數據使用的格式沒有做任何限制,但是對于多數目的來說,只發送傳統的表單數據是適合的,所以我的討論集中在服務器的響應上。響應也可以有基于文本的格式,但是正如它的名字表示的,XMLHttpRequest

具有內置的處理XML響應數據的能力。這使XML成為Ajax響應的默認選擇,所以我們從XML格式開始討論。從Java類產生XML把Ajax響應作為XML來傳遞有許多原因:每個支持Ajax的瀏覽器都有導航XML文檔的方法,也有許多服務器端技術可以處理XML數據。通過制定一個方案,描述要交換的文檔類型,在Ajax客戶端和服務器端之間很容易定義合約,而且如果服務器端架構采用面向服務的方式,那么使用XML也可以允許非Ajax客戶機使用您提供的數據。我將考慮從Java對象產生XML數據的三種方法,并討論每種方法的優劣。自行進行序列化首先,可以從對象圖以編程的方式生成XML。這種方式可以簡單到只是在每個JavaBean類中實現

toXml()

方法即可。然后就可以選擇合適的XMLAPI,讓每個bean提供表示自己狀態的元素,并遞歸地對自己的成員調用對象圖。顯然,這種方式無法擴展到大量的類,因為每個類都需要專門編寫自己的XML生成代碼。從好的方面來看,這是一個實現起來簡單的方式,沒有額外的配置支出或者更復雜的構建過程支出,任何JavaBean圖都可以只用幾個調用就變成XML文檔。在本系列

前一篇文章

的示例代碼中,我把XML標記字符串連接在一起,實現了

toXml()

方法。上次我就提到過,這是個糟糕的方法,因為它把確保標記配對、實體編碼等工作的負擔放在每個

toXml()

方法的代碼中。在Java平臺上有幾個XMLAPI可以替您做這些工作,這樣您就可以把精力集中在XML的內容上。清單1用JDOMAPI實現了在線商店示例中表示訂單的類中的

toXml()(請參閱

圖1)。

清單1.Order類的toXml()的JDOM實現 publicElementtoXml(){ElementelOrder=newElement("order");("id",id);("cost",getFormattedCost());ElementelDate=newElement("date").addContent(date);(elDate);ElementelItems=newElement("items");for(Iterator<Item>iter=();();){().toXml());}(elItems);returnelOrder;}在這里可以看到用JDOM創建元素、使用屬性和添加元素內容有多么簡單。遞歸地調用復合JavaBean的

toXml()

方法是為了取得它們子圖的

Element

表示。例如,items

元素的內容是通過調用

Order聚合的每個

Item

對象上的

toXml()

得到的。一旦所有的JavaBean都實現了

toXml()

方法,那么把任意對象圖序列化成XML文檔并返回給Ajax客戶機就簡單了,如清單2所示。

清單2.從JDOM元素生成XML響應 publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres)throwsServletException{StringcustId=("username");Customercustomer=getCustomer(custId);ElementresponseElem=();DocumentresponseDoc=newDocument(responseElem);("application/xml");newXMLOutputter().output(responseDoc,());}JDOM再次把工作變得非常簡單。只需要在對象圖返回的XML元素外面包裝一個

Document,然后用

XMLOutputter

把文檔寫入servlet響應即可。清單3顯示了用這種方式生成的XML示例,用JDOM

()

XMLOutputter

進行初始化,格式化得非常好。在這個示例中,顧客只做了一個訂單,包含兩個商品。

清單3.代表顧客的XML文檔 <xmlversion=""encoding="UTF-8"><customerusername="jimmy66"><realname>JamesHyrax</realname><orders><orderid="o-11123"cost="$"><date>08-26-2005</date><items><itemid="i-55768"><name>Oolong512MBCFCard</name><description>512MegabyteType1CompactFlashcard.ManufacturedbyOolongIndustries</description><price>$</price></item><itemid="i-74491"><name>FujakSuperpix72Camera</name><description>Megapixeldigitalcamerafeaturingsixshootingmodesand3xopticalzoom.Silver.</description><price>$</price></item></items></order></orders></customer>自行序列化的不足有趣的是,清單3中的代碼展示了讓JavaBean把自己序列化為XML的一個主要不足。假設要用這個文檔表示顧客的訂單歷史視圖。在這種情況下,不太可能要顯示每個歷史訂單中每個商品的完整說明,或者告訴顧客他或她自己的姓名。但是如果應用程序有一個

ProductSearch

類,它就是以

Item

bean列表的形式返回搜索結果,那么在

Item

的XML表示中包含說明可能會有幫助。而且,Item

類上代表當前庫存水平的額外字段,在產品搜索視圖中可能就是需要顯示的有用信息。但是,不管當前的庫存水平是否與當前情況相關(比如對顧客的訂單歷史來說),這個字段都會從包含

Item

的任何對象圖中序列化出來。從設計的角度來看,這是數據模型與視圖生成耦合的經典問題。每個bean只能用一種途徑序列化自己,一成不變的方式意味著Ajax交互最終要交換它們不需要交換的數據,因此造成客戶端代碼要從文檔中找到需要的信息更加困難,而且也會增加帶寬消耗和客戶端的XML解析時間。這種耦合的另一個后果就是XML的語法不能脫離Java類獨立變化。例如,對顧客文檔的方案做修改,可能會影響多個Java類,造成它們也不得不做修改和重新編譯。我稍后會解決這些問題,但是首先來看一個對自行序列化方式的可伸縮性問題的解決方案:XML綁定框架。XML綁定框架近些年來,已經開發了多個JavaAPI來簡化XML文檔到Java對象圖的綁定過程。多數都提供了XML編排和拆解;也就是說,它們可以在Java對象圖和XML之間執行雙向會話。這些框架封裝了XML處理的全部工作,這意味著應用程序代碼只需要處理普通的Java類。它們還希望提供有用的輔助功能,例如文檔驗證?;\統來說,這些框架采用了兩種不同的方式:代碼生成和對象到XML映射。我將分別解釋這兩種方式。代碼生成方式使用代碼生成的框架包括XMLBeans、JAXB、Zeus和JBind。Castor也能使用這項技術。這類框架的起點是描述文檔數據類型的XML方案。使用框架提供的工具,就可以生成代表這些方案定義類型的Java類。最后,用這些生成的類編寫應用程序,表示自己的模型數據,并通過框架提供的一些輔助機制把數據序列化成XML。如果應用程序要使用大型XML語法,那么代碼生成方式是個很好的方法。在數十個類上編寫定制XML序列化代碼的可伸縮性問題由此消除。另一方面,也不再需要定義自己的JavaBean。框架生成的Java類通常非常符合XML的結構,所以對它們進行編碼很難。而且,生成的類變成啞數據容器,因為一般不能向它們添加行為。一般來說,在應用程序代碼中要做些妥協,才能很好地處理方案生成的類型。另一個缺陷是如果修改方案,會造成生成的類也要修改,所以也就會對圍繞它們編寫的代碼帶來相應的影響。這種類型的XML綁定框架在數據拆解時最有用(例如,使用XML文檔并把它們轉化成Java對象)。除非擁有大型數據模型而且有可能從生成的類中獲益,否則基于代碼生成的框架對于Ajax應用程序來說可能有很大的殺傷力。映射方式采用映射方式的框架包括Castor和ApacheCommonsBetwixt。映射通常是比代碼生成更靈活和更輕量的解決方案。首先,可以像通常一樣編寫JavaBean,包括任何行為以及任何自己喜歡的方便的方法。然后,在運行時,調用框架中基于內省的編排器,并根據對象成員的類型、名稱和值生成XML文檔。通過定義類的映射文件,可以覆蓋默認的綁定策略,并就類在XML中的表示方式對編排器提出建議。這種方法是在可伸縮性與靈活性之間的良好折中??梢园凑兆约合矚g的方式編寫Java類,編排器負責處理XML。雖然映射定義文件編寫起來簡單,可伸縮性也足夠好,但是映射規則最多只能改變標準的綁定行為,而且在對象結構和它們的XML表示之間總要殘留一些耦合。最終,可能不得不在Java表示或XML格式之間任選一個做些折中,才能讓映射方法起作用。數據綁定總結DennisSosnoski就XML數據綁定API的主題,在代碼生成和代碼映射兩個方面寫了深入的文章。如果想進一步研究這個領域,我推薦他在Castor和代碼生成框架方面的精彩文章(請參閱

參考資料

中的鏈接)??傊a生成方式損失了過多的靈活性和方便性,對于典型的Ajax應用程序用處不大。另一方面,基于映射的框架可能工作得很好,但是要恰到好處地調整它們的映射策略,以便從對象生成需要的XML。所有的XML綁定API都具有手工序列化技術的一個主要不足:模型和視圖的耦合。被限制為一個類型一個XML表示,就意味著在網絡上總要有冗余數據傳輸。更嚴重的問題是,在情況要求客戶端代碼使用專門視圖時,客戶端代碼卻無法得到它,所以可能要費力地處理給定對象圖的一成不變的視圖。在傳統的Web應用程序開發中,采用頁面模板系統把視圖生成與控制器邏輯和模型數據干凈地分離。這種方法在Ajax場景中也會有幫助。頁面模板系統任何通用目的的頁面模板技術都可以用來生成XML,從而使Ajax應用程序根據自己的數據模型生成任何XML響應文檔。額外收獲是:模板可以用簡單的、表現力強的標記語言編寫,而不是用一行行的Java代碼編寫。清單5是一個JSP頁面,采用了

Customer

bean并表示出定制的XML視圖,適合客戶端代碼生成訂單歷史組件。

清單4.生成訂單歷史文檔的JSP <xmlversion=""><%@pagecontentType="application/xml"%><%@tagliburi=""prefix="c"%><c:setvar="cust"value="${}"/><orderhistoryusername="${}"><c:forEachvar="order"items="${}"><orderid="${}"cost="${}"><date>${}</date><items><c:forEachvar="item"items="${}"><itemid="${}"><name><c:outvalue="${}"escapeXml="true"/></name><price>${}</price></item></c:forEach></items></order></c:forEach></orderhistory>這個簡潔的模板只輸出訂單歷史視圖需要的數據,不輸出不相關的資料(例如商品說明)。創建產品搜索視圖的定制XML應當同樣簡單,這個視圖包含每個商品的完整說明和庫存水平。模板的問題另一方面,現在我需要為每個不同視圖創建一個新JSP,而不能僅僅把需要的對象圖組織起來并序列化它。從設計的角度來說,許多人可能會有爭議,認為這無論如何是件好事,因為這意味著正式地考慮服務器要生成的文檔類型。而且,因為我現在要處理通用的模板環境,而不是特定于XML的API,所以確保標記匹配、元素和屬性的順序正確以及XML實體(例如

<

&)正確轉義就成了我的責任。JSP的核心

out

標記使后面這項工作變得很容易,但是不是所有的模板技術都提供了這樣的機制。最后,沒有方便的途徑可以在服務器端根據方案檢驗生成的XML文檔的正確性,但這畢竟不是要在生產環境中做的事,可以方便地在開發期間處理它。不用XML的響應數據迄今為止,我介紹的所有技術都用XML文檔的形式生成服務器響應。但是,XML有一些問題。其中一個就是延遲。瀏覽器不能立即解析XML文檔并生成DOM模型,所以這會降低某些Ajax組件需要的“迅捷”感,特別是在較慢的機器上解析大型文檔的時候更是如此?!艾F場搜索”就是一個示例,在這種搜索中,當用戶輸入搜索術語時,就會從服務器提取搜索結果并顯示給用戶。對于現場搜索組件來說,迅速地響應輸入是非常重要的,但是同時它還需要迅速而持續地解析服務器的響應。延遲是一個重要的考慮因素,但是避免使用XML的最大原因是差勁的客戶端DOMAPI。清單5顯示了使用跨瀏覽器兼容的方式通過DOM得到某個值的時候,通常不得不面對的困難。

清單5.在JavaScript中導航XML響應文檔 用正則表達式處理XMLHttpRequest的responseText對象 varorderHistoryText=;varmatches=(/<date>(.*)<\/date>/);vardate=matches[1];在某些情況下,采用即時方式使用

responseText

會比較方便。但是,理想情況下,應當有種途徑,可以用一種能夠讓JavaScript輕松導航、卻沒有XML處理支出的格式表示復雜的結構化數據。幸運的是,確實存在這樣一種格式。JavaScript對象標注實際上,JavaScript對象的大部分都由聯合數組、數字索引數組、字符串、數字或者這些類型的嵌套組合而成。因為所有類型都可以用JavaScript直接聲明,所以可以在一條語句中靜態地定義對象圖。清單7使用JSON語法聲明了一個對象,并演示了如何訪問這個對象。大括號表示聯合數組(即對象),它的鍵-值組合由逗號分隔。方括號表示數字索引數組。

清單7.用JSON在JavaScript中直接聲明一個簡單對象 varband={name:"TheBeatles",members:[{name:"John",instruments:["Vocals","Guitar","Piano"]},{name:"Paul",instruments:["Vocals","Bass","Piano","Guitar"]},{name:"George",instruments:["Guitar","Vocals"]},{name:"Ringo",instruments:["Drums","Vocals"]}]};Order類的toJSONObject()方法實現 publicJSONObjecttoJSONObject(){JSONObjectjson=newJSONObject();("id",id);("cost",getFormattedCost());("date",date);JSONArrayjsonItems=newJSONArray();for(Iterator<Item>iter=();();){().toJSONObject());}("items",jsonItems);returnjson;}可以看到,

API非常簡單。

JSONObject

代表JavaScript對象(即聯合數組),有不同的

put()

方法,方法接受的

String

鍵和值是原生類型、String

類型或其他JSON類型。JSONArray

代表索引數組,所以它的

put()

方法只接受一個值。請注意在清單8中,創建

jsonItems

數組,然后再用

put()

把它附加到

json

對象上;可以用另外一種方法做這項工作,就是對每個項目調用("items",().toJSONObject());。accumulate()

方法與

put()

類似,區別在于它把值添加到按照鍵進行識別的索引數組。清單9顯示了如何序列化

JSONObject

并把它寫入servlet響應。

清單9.從JSONObject生成序列化的JSON響應 publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres)throwsServletException{ StringcustId=("username"); Customercustomer=getCustomer(custId); ("application/x-json"); ().print());}可以看到,它實際上什么也沒有做。在這里隱式調用的

JSONObject

toString()

方法做了所有工作。請注意,application/x-json

內容類型還有一點不確定——在編寫這篇文章的時候,關于JSON應當屬于什么MIME類型還沒有定論。但是,目前

application/x-json

是合理的選擇。清單10顯示了這個servlet代碼的示例響應。

清單10.Customerbean的JSON表示 {"orders":[{"items":[{"price":"$","description":"512MegabyteType1CompactFlashcard.ManufacturedbyOolongIndustries","name":"Oolong512MBCFCard","id":"i-55768"},{"price":"$","description":"Megapixeldigitalcamerafeaturingsixshootingmodesand3xopticalzoom.Silver.","name":"FujakSuperpix72Camera","id":"i-74491"}],"date":"08-26-2005","cost":"$","id":"o-11123"}],"realname":"JamesHyrax","username":"jimmy66"}在客戶端使用JSON處理的最后一步是把在客戶端把JSON數據變成JavaScript對象。這可以通過對

eval()

的簡單調用實現,這個函數可以即時地解釋包含JavaScript表達式的字符串。清單11把JSON響應轉變成JavaScript對象圖,然后執行清單5的任務,從顧客的最后一次訂單中得到第一個商品的名稱。

清單11.評估JSON響應 varjsonExpression="("++")";varcustomer=eval(jsonExpression);ame;比較清單11和

清單5

可以發現使用JSON的客戶端的優勢。如果在Ajax項目中要在客戶端對許多復雜的服務器響應進行導航,那么JSON可能適合您的需要。JSON和

XMLHttpRequest

結合還會讓Ajax交互看起來更像RPC調用而不是SOA請求,這對應用程序的設計可能會有意義。在下一篇文章中,我要研究的框架,就是明確地為了讓JavaScript代碼對服務器端對象進行遠程方法調用而設計的。JSON的不足JSON也有它的不足。使用這里介紹的JSON方式,就沒有辦法針對每個請求對對象的序列化進行裁剪,所以不需要的字段可能經常會在網絡上發送。另外,添加

toJSONObject()

方法到每個JavaBean,可伸縮性不太好,雖然用內省和標注編寫一個通用的JavaBean到JSON的序列化器可能很簡單。最后,如果服務器端代碼是面向服務的,沒有單獨針對處理Ajax客戶請求調整過,那么由于對XML一致的支持,XML會是更好的選擇。比較序列化技術現在已經看到了把Java狀態傳輸到Ajax客戶端的五種不同技術。我討論了自行手工編碼XML序列化、通過代碼生成的XML綁定、通過映射機制的XML綁定、基于模板的XML生成以及手工編碼到JSON的序列化。每種技術都有自己的優勢和不足,分別適用于不同的應用程序架構。為了總結每種方式的優勢與不足,表1從六個方面進行了粗略的評分:可伸縮性描述技術適應大量數據類型的容易程度。對于每個附加類型,編碼和

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論