<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent.Chan‘s Blog

    常用鏈接

    統計

    積分與排名

    網站

    最新評論

    3、面向 Java 開發人員的 Ajax: 構建動態的 Java 應用程序

    Ajax?為更好的?Web?應用程序鋪平了道路

    級別:?中級

    Philip?McCarthy?,?軟件開發顧問,?獨立咨詢顧問


    2005?年?10?月?20?日

    在?Web?應用程序開發中,頁面重載循環是最大的一個使用障礙,對于?Java&#8482;?開發人員來說也是一個嚴峻的挑戰。在這個系列中,作者?Philip?McCarthy?介紹了一種創建動態應用程序體驗的開創性方式。Ajax(異步?javascript?和?XML)是一種編程技術,它允許為基于?Java?的?Web?應用程序把?Java?技術、XML?和?javascript?組合起來,從而打破頁面重載的范式。
    Ajax(即異步?javascript? 和?XML)是一種?Web?應用程序開發的手段,它采用客戶端腳本與?Web?服務器交換數據。所以,不必采用會中斷交互的完整頁面刷新,就可以動態地 更新?Web?頁面。使用?Ajax,可以創建更加豐富、更加動態的?Web?應用程序用戶界面,其即時性與可用性甚至能夠接近本機桌面應用程序。

    Ajax?不是一項技術,而更像是一個?模式?——?一種識別和描述有用的設計技術的方式。Ajax?是新穎的,因為許多開發人員才剛剛開始知道 它,但是所有實現?Ajax?應用程序的組件都已經存在若干年了。它目前受到重視是因為在?2004?和?2005?年出現了一些基于?Ajax?技術的 非常棒的動態?Web?UI,最著名的就是?Google?的?GMail?和?Maps?應用程序,以及照片共享站點?Flickr。這些用戶界面具有 足夠的開創性,有些開發人員稱之為“Web?2.0”,因此對?Ajax?應用程序的興趣飛速上升。

    在這個系列中,我將提供使用?Ajax?開發應用程序需要的全部工具?。在第一篇文章中,我將解釋?Ajax?背后的概念,演示為基于?Java? 的?Web?應用程序創建?Ajax?界面的基本步驟。我將使用代碼示例演示讓?Ajax?應用程序如此動態的服務器端?Java?代碼和客戶端?javascript。最后,我將指出?Ajax?方式的一些不足,以及在創建?Ajax?應用程序時應當考慮的一些更廣的可用性和訪問性問題。

    更好的購物車

    可以用?Ajax?增強傳統的?Web?應用程序,通過消除頁面裝入從而簡化交互。為了演示這一點,我采用一個簡單的購物車示例,在向里面添加項目 時,它會動態更新。這項技術如果整合到在線商店,那么用戶可以持續地瀏覽和向購物車中添加項目,而不必在每次點擊之后都等候完整的頁面更新。雖然這篇文章 中的有些代碼特定于購物車示例,但是演示的技術可以應用于任何?Ajax?應用程序。清單?1?顯示了購物車示例使用的有關?HTML?代碼,整篇文章中 都會使用這個?HTML。


    清單1.?購物車示例的有關片斷

    <!--?Table?of?products?from?store's?catalog,?one?row?per?item?-->
    <th>Name</th>?<th>Description</th>?<th>Price</th>?<th></th>
    ...
    <tr>
    ??<!--?Item?details?-->
    ??<td>Hat</td>?<td>Stylish?bowler?hat</td>?<td>$19.99</td>
    ??<td>
    ????<!--?Click?button?to?add?item?to?cart?via?Ajax?request?-->
    ????<button?onclick="addToCart('hat001')">Add?to?Cart</button>
    ??</td>
    </tr>
    ...

    <!--?Representation?of?shopping?cart,?updated?asynchronously?-->
    <ul?id="cart-contents">

    ??<!--?List-items?will?be?added?here?for?each?item?in?the?cart?-->
    ??
    </ul>

    <!--?Total?cost?of?items?in?cart?displayed?inside?span?element?-->
    Total?cost:?<span?id="total">$0.00</span>


    Ajax?往返過程

    Ajax?交互開始于叫作?XMLHttpRequest?的?javascript?對象。顧名思義,它允許客戶端腳本執行 ?HTTP?請求,并解析?XML?服務器響應。Ajax?往返過程的第一步是創建?XMLHttpRequest?的實例。在 ?XMLHttpRequest?對象上設置請求使用的?HTTP?方法(GET?或?POST)以及目標?URL。

    現在,您還記得?Ajax?的第一個?a?是代表?異步(asynchronous)?嗎?在發送?HTTP?請求時,不想讓瀏覽器掛著等候服務器 響應。相反,您想讓瀏覽器繼續對用戶與頁面的交互進行響應,并在服務器響應到達時再進行處理。為了實現這個要求,可以在?XMLHttpRequest? 上注冊一個回調函數,然后異步地分派?XMLHttpRequest。然后控制就會返回瀏覽器,當服務器響應到達時,會調用回調函數。

    在?Java?Web?服務器上,請求同其他?HttpServletRequest?一樣到達。在解析了請求參數之后,servlet?調用必要的應用程序邏輯,把響應序列化成?XML,并把?XML?寫入?HttpServletResponse。

    回到客戶端時,現在調用注冊在?XMLHttpRequest?上的回調函數,處理服務器返回的?XML?文檔。最后,根據服務器返回的數據,用?javascript?操縱頁面的?HTML?DOM,把用戶界面更新。圖?1?是?Ajax?往返過程的順序圖。


    圖?1.?Ajax?往返過程

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


    分派?XMLHttpRequest

    我將從?Ajax?序列的起點開始:創建和分派來自瀏覽器的?XMLHttpRequest。不幸的是,不同的瀏覽器創建?XMLHttpRequest?的方法各不相同。清單?2?的?javascript?函數消除了這些依賴于瀏覽器的技巧,它可以檢測當前瀏覽器要使用的正確方式,并返回一個可以使用的?XMLHttpRequest。最好是把它當作輔助代碼:只要把它拷貝到?javascript?庫,并在需要?XMLHttpRequest?的時候使用它就可以了。


    清單?2.?創建跨瀏覽器的?XMLHttpRequest

    /*
    ?*?Returns?a?new?XMLHttpRequest?object,?or?false?if?this?browser
    ?*?doesn't?support?it
    ?*/
    function?newXMLHttpRequest()?{

    ??var?xmlreq?=?false;

    ??if?(window.XMLHttpRequest)?{

    ????//?Create?XMLHttpRequest?object?in?non-Microsoft?browsers
    ????xmlreq?=?new?XMLHttpRequest();

    ??}?else?if?(window.ActiveXObject)?{

    ????//?Create?XMLHttpRequest?via?MS?ActiveX
    ????try?{
    ??????//?Try?to?create?XMLHttpRequest?in?later?versions
    ??????//?of?Internet?Explorer

    ??????xmlreq?=?new?ActiveXObject("Msxml2.XMLHTTP");

    ????}?catch?(e1)?{

    ??????//?Failed?to?create?required?ActiveXObject

    ??????try?{
    ????????//?Try?version?supported?by?older?versions
    ????????//?of?Internet?Explorer

    ????????xmlreq?=?new?ActiveXObject("Microsoft.XMLHTTP");

    ??????}?catch?(e2)?{

    ????????//?Unable?to?create?an?XMLHttpRequest?with?ActiveX
    ??????}
    ????}
    ??}

    ??return?xmlreq;
    }
    ??
    ?


    稍后我將討論處理那些不支持?XMLHttpRequest?的瀏覽器的技術。目前,示例假設清單?2?的?newXMLHttpRequest?函數總能返回?XMLHttpRequest?實例。

    返回示例的購物車場景,我想要當用戶在目錄項目上點擊?Add?to?Cart?時啟動?Ajax?交互。名為?addToCart()?的?onclick?處理函數負責通過?Ajax?調用來更新購物車的狀態(請參閱?清單?1)。正如清單?3?所示,addToCart()?需要做的第一件事是通過調用清單?2?的?newXMLHttpRequest()?函數得到?XMLHttpRequest?對象。接下來,它注冊一個回調函數,用來接收服務器響應(我稍后再詳細解釋這一步;請參閱?清單?6)。

    因為請求會修改服務器上的狀態,所以我將用?HTTP?POST?做這個工作。通過?POST?發送數據要求三個步驟。第一,需要打開與要通信的服 務器資源的?POST?連接?——?在這個示例中,服務器資源是一個映射到?URL?cart.do?的?servlet。然后,我在 ?XMLHttpRequest?上設置一個頭,指明請求的內容是表單?編碼的數據。最后,我用表單編碼的數據作為請求體發送請求。

    清單?3?把這些步驟放在了一起。


    清單?3.?分派?Add?to?Cart?XMLHttpRequest

    /*
    ?*?Adds?an?item,?identified?by?its?product?code,?to?the?shopping?cart
    ?*?itemCode?-?product?code?of?the?item?to?add.
    ?*/
    function?addToCart(itemCode)?{

    ??//?Obtain?an?XMLHttpRequest?instance
    ??var?req?=?newXMLHttpRequest();

    ??//?Set?the?handler?function?to?receive?callback?notifications
    ??//?from?the?request?object
    ??var?handlerFunction?=?getReadyStateHandler(req,?updateCart);
    ??req.onreadystatechange?=?handlerFunction;
    ??
    ??//?Open?an?HTTP?POST?connection?to?the?shopping?cart?servlet.
    ??//?Third?parameter?specifies?request?is?asynchronous.
    ??req.open("POST",?"cart.do",?true);

    ??//?Specify?that?the?body?of?the?request?contains?form?data
    ??req.setRequestHeader("Content-Type",?
    ???????????????????????"application/x-www-form-urlencoded");

    ??//?Send?form?encoded?data?stating?that?I?want?to?add?the?
    ??//?specified?item?to?the?cart.
    ??req.send("action=add&item="+itemCode);
    }


    這就是建立?Ajax?往返過程的第一部分,即創建和分派來自客戶機的?HTTP?請求。接下來是用來處理請求的?Java?servlet?代碼。


    servlet?請求處理

    用?servlet?處理?XMLHttpRequest,與處理普通的瀏覽器?HTTP?請求一樣。可以用 ?HttpServletRequest.getParameter()?得到在?POST?請求體中發送的表單編碼數據。Ajax?請求被放進與來自應 用程序的常規?Web?請求一樣的?HttpSession?中。對于示例購物車場景來說,這很有用,因為這讓我可以把購物車狀態封裝在 ?JavaBean?中,并在請求之間在會話中維持這個狀態。

    清單?4?是處理?Ajax?請求、更新購物車的簡單?servlet?的一部分。Cart?bean?是從用戶會話中獲得的,并根據請求參數更新 它的狀態。然后?Cart?被序列化成?XML,XML?又被寫入?ServletResponse。重要的是把響應的內容類型設置為 ?application/xml,否則?XMLHttpRequest?不會把響應內容解析成?XML?DOM。


    清單?4.?處理?Ajax?請求的?servlet?代碼

    public?void?doPost(HttpServletRequest?req,?HttpServletResponse?res)
    ????????????????????????throws?java.io.IOException?{

    ??Cart?cart?=?getCartFromSession(req);

    ??String?action?=?req.getParameter("action");
    ??String?item?=?req.getParameter("item");
    ??
    ??if?((action?!=?null)&&(item?!=?null))?{

    ????//?Add?or?remove?items?from?the?Cart
    ????if?("add".equals(action))?{
    ??????cart.addItem(item);

    ????}?else?if?("remove".equals(action))?{
    ??????cart.removeItems(item);

    ????}
    ??}

    ??//?Serialize?the?Cart's?state?to?XML
    ??String?cartXml?=?cart.toXml();

    ??//?Write?XML?to?response.
    ??res.setContentType("application/xml");
    ??res.getWriter().write(cartXml);
    }

    ?


    清單?5?顯示了?Cart.toXml()?方法生成的示例?XML。它很簡單。請注意?cart?元素的?generated?屬性,它是?System.currentTimeMillis()?生成的一個時間戳。


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

    <?xml?version="1.0"?>
    <cart?generated="1123969988414"?total="$171.95">
    ??<item?code="hat001">
    ????<name>Hat</name>
    ????<quantity>2</quantity>
    ??</item>
    ??<item?code="cha001">
    ????<name>Chair</name>
    ????<quantity>1</quantity>
    ??</item>
    ??<item?code="dog001">
    ????<name>Dog</name>
    ????<quantity>1</quantity>
    ??</item>
    </cart>

    ?


    如果查看應用程序源代碼(可以從?下載?一節得到)中的?Cart.java,可以看到生成?XML?的方式只是把字符串添加在一起。雖然對這個示例來說足夠了,但是對于從?Java?代碼生成?XML?來說則是最差的方式。我將在這個系列的下一期中介紹一些更好的方式。

    現在您已經知道了?CartServlet?響應?XMLHttpRequest?的方式。下一件事就是返回客戶端,查看如何用?XML?響應更新頁面狀態。


    用?javascript?進行響應處理

    XMLHttpRequest?的?readyState?屬性是一個數值,它指出請求生命周期的狀態。它從?0(代表“未初始化”)變化到?4 (代表“完成”)。每次?readyState?變化時,readystatechange?事件就觸發,由?onreadystatechange?屬 性指定的事件處理函數就被調用。

    在?清單?3?中已經看到了如何調用?getReadyStateHandler()?函數創建事件處理函數。然后把這個事件處理函數分配給?onreadystatechange?屬性。getReadyStateHandler()?利用了這樣一個事實:函數是?javascript? 中的一級對象。這意味著函數可以是其他函數的參數,也可以創建和返回其他函數。getReadyStateHandler()?的工作是返回一個函數,檢 查?XMLHttpRequest?是否已經完成,并把?XML?響應傳遞給調用者指定的事件處理函數。清單?6?是 ?getReadyStateHandler()?的代碼。


    清單?6.?getReadyStateHandler()?函數

    /*
    ?*?Returns?a?function?that?waits?for?the?specified?XMLHttpRequest
    ?*?to?complete,?then?passes?its?XML?response?to?the?given?handler?function.
    ?*?req?-?The?XMLHttpRequest?whose?state?is?changing
    ?*?responseXmlHandler?-?Function?to?pass?the?XML?response?to
    ?*/
    function?getReadyStateHandler(req,?responseXmlHandler)?{

    ??//?Return?an?anonymous?function?that?listens?to?the?
    ??//?XMLHttpRequest?instance
    ??return?function?()?{

    ????//?If?the?request's?status?is?"complete"
    ????if?(req.readyState?==?4)?{
    ??????
    ??????//?Check?that?a?successful?server?response?was?received
    ??????if?(req.status?==?200)?{

    ????????//?Pass?the?XML?payload?of?the?response?to?the?
    ????????//?handler?function
    ????????responseXmlHandler(req.responseXML);

    ??????}?else?{

    ????????//?An?HTTP?problem?has?occurred
    ????????alert("HTTP?error:?"+req.status);
    ??????}
    ????}
    ??}
    }

    ?

    按此在新窗口瀏覽圖片?HTTP?狀態碼

    在清單?6?中,檢查?XMLHttpRequest?的?status?屬性以查看請求是否成功完成。status?包含服務器響應的 ?HTTP?狀態碼。在執行簡單的?GET?和?POST?請求時,可以假設任何大于?200?(OK)的碼都是錯誤。如果服務器發送重定向響應(例如 ?301?或?302),瀏覽器會透明地進行重定向并從新的位置獲取資源;XMLHttpRequest?看不到重定向狀態碼。而且,瀏覽器會自動添加 ?Cache-Control:?no-cache?頭到所有?XMLHttpRequest,這樣客戶代碼永遠也不用處理?304(未經修改)服務器響 應。
    ?
    ?
    關于?getReadyStateHandler()

    getReadyStateHandler()?是段相對復雜的代碼,特別是如果您不習慣閱讀?javascript?的話。但是通過把這個函數放在?javascript?庫中,就可以處理?Ajax?服務器響應,而不必處理?XMLHttpRequest?的內部細節。重要的是要理解如何在自己的代碼中使用?getReadyStateHandler()。

    在?清單?3? 中看到了?getReadyStateHandler()?像這樣被調用:handlerFunction?= ?getReadyStateHandler(req,?updateCart)。在這個示例中,getReadyStateHandler()?返回的 函數將檢查在?req?變量中的?XMLHttpRequest?是否已經完成,然后用響應的?XML?調用名為?updateCart?的函數。

    提取購物車數據

    清單?7?是?updateCart()?本身的代碼。函數用?DOM?調用檢查購物車的?XML?文檔,然后更新?Web?頁面(請參閱?清單?1), 反映新的購物車內容。這里的重點是用來從?XML?DOM?提取數據的調用。cart?元素的?generated?屬性是在?Cart?序列化為 ?XML?時生成的一個時間戳,檢查它可以保證新的購物車數據不會被舊的數據覆蓋。Ajax?請求天生是異步的,所以這個檢查可以處理服務器響應未按次序 到達的情況。


    清單?7.?更新頁面,反映購物車的?XML?文檔

    function?updateCart(cartXML)?{

    ?//?Get?the?root?"cart"?element?from?the?document
    ?var?cart?=?cartXML.getElementsByTagName("cart")[0];

    ?//?Check?that?a?more?recent?cart?document?hasn't?been?processed
    ?//?already
    ?var?generated?=?cart.getAttribute("generated");
    ?if?(generated?>?lastCartUpdate)?{
    ???lastCartUpdate?=?generated;

    ???//?Clear?the?HTML?list?used?to?display?the?cart?contents
    ???var?contents?=?document.getElementById("cart-contents");
    ???contents.innerHTML?=?"";

    ???//?Loop?over?the?items?in?the?cart
    ???var?items?=?cart.getElementsByTagName("item");
    ???for?(var?I?=?0?;?I?<?items.length?;?I++)?{

    ?????var?item?=?items[I];

    ?????//?Extract?the?text?nodes?from?the?name?and?quantity?elements
    ?????var?name?=?item.getElementsByTagName("name")[0]
    ???????????????????????????????????????????????.firstChild.nodevalue;
    ???????????????????????????????????????????????
    ?????var?quantity?=?item.getElementsByTagName("quantity")[0]
    ???????????????????????????????????????????????.firstChild.nodevalue;

    ?????//?Create?and?add?a?list?item?HTML?element?for?this?cart?item
    ?????var?li?=?document.createElement("li");
    ?????li.appendChild(document.createTextNode(name+"?x?"+quantity));
    ?????contents.appendChild(li);
    ???}
    ?}

    ?//?Update?the?cart's?total?using?the?value?from?the?cart?document
    ?document.getElementById("total").innerHTML?=?
    ??????????????????????????????????????????cart.getAttribute("total");
    }

    ?


    到此,整個?Ajax?往返過程完成了,但是您可能想讓?Web?應用程序運行一下查看實際效果(請參閱?下載?一節)。這個示例非常簡單,有很多需要改進之處。例如,我包含了從購物車中清除項目的服務器端代碼,但是無法從?UI?訪問它。作為一個好的練習,請試著在應用程序現有的?javascript?代碼之上構建出能夠實現這個功能的代碼。


    使用?Ajax?的挑戰

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

    XMLHttpRequest?的可用性

    Ajax?開發人員面臨的一個最大問題是:在沒有?XMLHttpRequest?可用時該如何響應?雖然主要的現代瀏覽器都支持 ?XMLHttpRequest,但仍然有少數用戶的瀏覽器不支持,或者瀏覽器的安全設置阻止使用?XMLHttpRequest。如果開發的?Web? 應用程序要部署在企業內部網,那么可能擁有指定支持哪種瀏覽器的權力,從而可以認為?XMLHttpRequest?總能使用。但是,如果要部署在公共 ?Web?上,那么就必須當心,如果假設?XMLHttpRequest?可用,那么就可能會阻止那些使用舊的瀏覽器、殘疾人專用瀏覽器和手持設備上的輕 量級瀏覽器的用戶使用您的應用程序。

    所以,您應當努力讓應用程序“平穩降級”,在沒有?XMLHttpRequest?支持的瀏覽器中也能夠工作。在購物車的示例中,把應用程序降級的 最好方式可能是讓?Add?to?Cart?按鈕執行一個常規的表單提交,刷新頁面來反映購物車更新后的狀態。Ajax?的行為應當在頁面裝入的時候就通 過?javascript?添加到頁面,只有在?XMLHttpRequest?可用時才把?javascript?事件處理函數附加到每個?Add?to?Cart?按鈕。另一種方式是在用戶登錄時檢測?XMLHttpRequest?是否可用,然后相應地提供應用程序的?Ajax?版本或基于表單的普通版本。

    可用性考慮

    關于?Ajax?應用程序的某些可用性問題比較普遍。例如,讓用戶知道他們的輸入已經注冊了可能是重要的,因為沙漏光標和?spinning?瀏覽 器的常用反饋機制“throbber”對?XMLHttpRequest?不適用。一種技術是用“Now?updating...”類型的信息替換 ?Submit?按鈕,這樣用戶在等候響應期間就不會反復單擊按鈕了。

    另一個問題是,用戶可能沒有注意到他們正在查看的頁面的某一部分已經更新了??梢允褂貌煌目梢暭夹g,把用戶的眼球帶到頁面的更新區域,從而緩解這 個問題。由?Ajax?更新頁面造成的其他問題還包括:“破壞了”瀏覽器的后退按鈕,地址欄中的?URL?也無法反映頁面的整個狀態,妨礙了設置書簽。請 參閱?參考資料?一節,獲得專門解決?Ajax?應用程序可用性問題的文章。

    服務器負載

    用?Ajax?實現代替普通的基于表單的?UI,會大大提高對服務器發出的請求數量。例如,一個普通的?Google?Web?搜索對服務器只有一 個請求,是在用戶提交搜索表單時出現的。而?Google?Suggest?試圖自動完成搜索術語,它要在用戶輸入時向服務器發送多個請求。在開發 ?Ajax?應用程序時,要注意將要發送給服務器的請求數量以及由此造成的服務器負荷。降低服務器負載的辦法是,在客戶機上對請求進行緩沖并且緩存服務器 響應(如果可能的話)。還應該嘗試將?Ajax?Web?應用程序設計為在客戶機上執行盡可能多的邏輯,而不必聯絡服務器。

    處理異步

    非常重要的是,要理解無法保證?XMLHttpRequest?會按照分派它們的順序完成。實際上,應當假設它們不會按順序完成,并且在設計應用程序時把這一點記在心上。在購物車的示例中,使用最后更新的時間戳來確保新的購物車數據不會被舊的數據覆蓋(請參閱?清單?7)。這個非?;镜姆绞娇梢杂糜谫徫镘噲鼍?,但是可能不適合其他場景。所以在設計時請考慮如何處理異步的服務器響應。


    結束語

    現在您對?Ajax?的基本原則應當有了很好的理解,對參與?Ajax?交互的客戶端和服務器端組件也應當有了初步的知識。這些是基于?Java? 的?Ajax?Web?應用程序的構造塊。另外,您應當理解了伴隨?Ajax?方式的一些高級設計問題。創建成功的?Ajax?應用程序要求整體考慮,從 ?UI?設計到?javascript?設計,再到服務器端架構;但是您現在應當已經武裝了考慮其他這些方面所需要的核心?Ajax?知識。

    如果使用這里演示的技術編寫大型?Ajax?應用程序的復雜性讓您覺得恐慌,那么有好消息給您。由于?Struts、Spring?和 ?Hibernate?這類框架的發展把?Web?應用程序開發從底層?Servlet?API?和?JDBC?的細節中抽象出來,所以正在出現簡化 ?Ajax?開發的工具包。其中有些只側重于客戶端,提供了向頁面添加可視效果的簡便方式,或者簡化了對?XMLHttpRequest?的使用。有些則 走得更遠,提供了從服務器端代碼自動生成?Ajax?接口的方式。這些框架替您完成了繁重的任務,所以您可以采用更高級的方式進行?Ajax?開發。我在 這個系列中將研究其中的一些。

    Ajax?社區正在快速前進,所以會有大量有價值的信息涌現。在閱讀這個系列的下一期之前,我建議您參考?參考資料?一節中列出的文章,特別是如果您是剛接觸?Ajax?或客戶端開發的話。您還應當花些時間研究示例源代碼并考慮一些增強它的方式。

    在這個系列的下一篇文章中,我將深入討論?XMLHttpRequest?API,并推薦一些從?JavaBean?方便地創建?XML?的方式。我還將介紹替代?XML?進行?Ajax?數據傳遞的方式,例如?JSON(javascript?Object?Notation)輕量級數據交換格式。

    下載

    描述?名字?大小??下載方法?
    Sample?code?j-ajax1.zip?8?KB??FTP?
    按此在新窗口瀏覽圖片?
    按此在新窗口瀏覽圖片?關于下載方法的信息?按此在新窗口瀏覽圖片?按此在新窗口瀏覽圖片?獲取?Adobe??Reader??

    posted on 2006-02-19 10:51 草兒 閱讀(4) 評論(0) ?編輯?收藏收藏至365K

    posted on 2006-03-18 18:58 Vincent.Chen 閱讀(191) 評論(0)  編輯  收藏 所屬分類: AJAX

    主站蜘蛛池模板: 羞羞漫画在线成人漫画阅读免费| 亚洲冬月枫中文字幕在线看| 无码人妻一区二区三区免费视频| 日本成人免费在线| 亚洲AV永久无码精品一福利| 浮力影院第一页小视频国产在线观看免费 | 免费一级黄色毛片| 国产亚洲Av综合人人澡精品| 全黄性性激高免费视频| 免费看一级高潮毛片| 曰韩亚洲av人人夜夜澡人人爽| 中文字幕av免费专区| 中文字幕亚洲色图| 一色屋成人免费精品网站| 亚洲综合一区二区三区四区五区| 亚洲黄色网址在线观看| 久久A级毛片免费观看| 亚洲国产成人久久精品app| 偷自拍亚洲视频在线观看| 亚洲午夜爱爱香蕉片| 四虎国产精品免费永久在线| 久久夜色精品国产噜噜亚洲AV| 噼里啪啦免费观看高清动漫4| 亚洲日本va一区二区三区| 亚洲精品无码专区2| 免费视频精品一区二区三区 | 国产在线19禁免费观看| 久久久精品视频免费观看| 亚洲国产精品第一区二区| 91在线品视觉盛宴免费| 日本一区二区三区在线视频观看免费 | 亚洲6080yy久久无码产自国产| 亚洲日韩涩涩成人午夜私人影院| 在线观看人成视频免费无遮挡| 亚洲成A∨人片在线观看无码| 国产美女做a免费视频软件| 99在线免费观看| 亚洲最大中文字幕无码网站| 国产午夜亚洲精品理论片不卡| 无码人妻精品中文字幕免费东京热| 国产精品亚洲一区二区三区久久|