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

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

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

    無為

    無為則可為,無為則至深!

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      190 Posts :: 291 Stories :: 258 Comments :: 0 Trackbacks

    理解 Ajax 編程的基本知識 是重要的,但是如果正在構建復雜的用戶界面,那么能夠在更高層次的抽象上工作也很重要。在面向 Java 開發人員的 Ajax 系列的第 3 篇文章中,我在上個月的 Ajax 的數據序列化技術 基礎之上,介紹一種可以避免繁瑣的 Java 對象序列化細節的技術。

    上一篇文章 中,我介紹了如何用 JavaScript 對象標注(JSON)以一種在客戶機上容易轉化成 JavaScript 對象的格式對數據進行序列化。有了這個設置,就可以用 JavaScript 代碼調用遠程服務,并在響應中接收 JavaScript 對象圖,但是又不像遠程過程調用。這一次,將學習如何更進一步,使用一個框架,把從 JavaScript 客戶代碼對服務器端 Java 對象進行遠程調用的能力正式化。

    DWR 是一個開放源碼的使用 Apache 許可協議的解決方案,它包含服務器端 Java 庫、一個 DWR servlet 以及 JavaScript 庫。雖然 DWR 不是 Java 平臺上唯一可用的 Ajax-RPC 工具包,但是它是最成熟的,而且提供了許多有用的功能。請參閱 參考資料 ,在繼續學習之前下載 DWR。

    DWR 是什么?

    從最簡單的角度來說,DWR 是一個引擎,可以把服務器端 Java 對象的方法公開給 JavaScript 代碼。使用 DWR 可以有效地從應用程序代碼中把 Ajax 的全部請求-響應循環消除掉。這意味著客戶端代碼再也不需要直接處理 XMLHttpRequest 對象或者服務器的響應。不再需要編寫對象的序列化代碼或者使用第三方工具才能把對象變成 XML。甚至不再需要編寫 servlet 代碼把 Ajax 請求調整成對 Java 域對象的調用。

    DWR 是作為 Web 應用程序中的 servlet 部署的。把它看作一個黑盒子,這個 servlet 有兩個主要作用:首先,對于公開的每個類,DWR 動態地生成包含在 Web 頁面中的 JavaScript。生成的 JavaScript 包含存根函數,代表 Java 類上的對應方法并在幕后執行 XMLHttpRequest。這些請求被發送給 DWR,這時它的第二個作用就是把請求翻譯成服務器端 Java 對象上的方法調用并把方法的返回值放在 servlet 響應中發送回客戶端,編碼成 JavaScript。DWR 還提供了幫助執行常見的用戶界面任務的 JavaScript 工具函數。



    回頁首


    關于示例

    在更詳細地解釋 DWR 之前,我要介紹一個簡單的示例場景。像在前一篇文章中一樣,我將采用一個基于在線商店的最小模型,這次包含一個基本的產品表示、一個可以包含產品商品的用戶購物車以及一個從數據存儲查詢產品的數據訪問對象(DAO)。Item 類與前一篇文章中使用的一樣,但是不再實現任何手工序列化方法。圖 1 說明了這個簡單的設置:


    圖 1. 說明 Cart、CatalogDAO 和 Item 類的類圖

    在這個場景中,我將演示兩個非常簡單的用例。第一,用戶可以在目錄中執行文本搜索并查看匹配的商品。第二,用戶可以添加商品到購物車中并查看購物車中商品的總價。



    回頁首


    實現目錄

    DWR 應用程序的起點是編寫服務器端對象模型。在這個示例中,我從編寫 DAO 開始,用它提供對產品目錄數據存儲的搜索功能。CatalogDAO.java 是一個簡單的無狀態的類,有一個無參數的構造函數。清單 1 顯示了我想要公開給 Ajax 客戶的 Java 方法的簽名:


    清單 1. 通過 DWR 公開的 CatalogDAO 方法
    												
    														/**
     * Returns a list of items in the catalog that have 
     *  names or descriptions matching the search expression
     * @param expression Text to search for in item names 
     *  and descriptions 
     * @return list of all matching items
     */
    public List<Item> findItems(String expression);
    
    /**
     * Returns the Item corresponding to a given Item ID
     * @param id The ID code of the item
     * @return the matching Item
     */
    public Item getItem(String id);
    
    												
    										

    接下來,我需要配置 DWR,告訴它 Ajax 客戶應當能夠構建 CatalogDAO 并調用這些方法。我在清單 2 所示的 dwr.xml 配置文件中做這些事:


    清單 2. 公開 CatalogDAO 方法的配置
    												
    														<!DOCTYPE dwr PUBLIC
      "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
      "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
    <dwr>
      <allow>
        <create creator="new" javascript="catalog">
          <param name="class" 
            value="developerworks.ajax.store.CatalogDAO"/>
          <include method="getItem"/> 
          <include method="findItems"/> 
        </create> 
        <convert converter="bean" 
          match="developerworks.ajax.store.Item">
          <param name="include" 
            value="id,name,description,formattedPrice"/>
        </convert>
      </allow>
    </dwr>
    
    												
    										

    dwr.xml 文檔的根元素是 dwr。在這個元素內是 allow 元素,它指定 DWR 進行遠程的類。allow 的兩個子元素是 createconvert

    create 元素

    create 元素告訴 DWR 應當公開給 Ajax 請求的服務器端類,并定義 DWR 應當如何獲得要進行遠程的類的實例。這里的 creator 屬性被設置為值 new,這意味著 DWR 應當調用類的默認構造函數來獲得實例。其他的可能有:通過代碼段用 Bean 腳本框架(Bean Scripting Framework,BSF)創建實例,或者通過與 IOC 容器 Spring 進行集成來獲得實例。默認情況下,到 DWR 的 Ajax 請求會調用 creator,實例化的對象處于頁面范圍內,因此請求完成之后就不再可用。在無狀態的 CatalogDAO 情況下,這樣很好。

    createjavascript 屬性指定從 JavaScript 代碼訪問對象時使用的名稱。嵌套在 create 元素內的 param 元素指定 creator 要創建的 Java 類。最后,include 元素指定應當公開的方法的名稱。顯式地說明要公開的方法是避免偶然間允許訪問有害功能的良好實踐 —— 如果漏了這個元素,類的所有方法都會公開給遠程調用。反過來,可以用 exclude 元素指定那些想防止被訪問的方法。

    convert 元素

    creator 負責公開用于 Web 遠程的類和類的方法,convertor 則負責這些方法的參數和返回類型。convert 元素的作用是告訴 DWR 在服務器端 Java 對象表示和序列化的 JavaScript 之間如何轉換數據類型。

    DWR 自動地在 Java 和 JavaScript 表示之間調整簡單數據類型。這些類型包括 Java 原生類型和它們各自的類表示,還有 String、Date、數組和集合類型。DWR 也能把 JavaBean 轉換成 JavaScript 表示,但是出于安全性的原因,做這件事要求顯式的配置。

    清單 2 中的 convert 元素告訴 DWR 用自己基于反射的 bean 轉換器處理 CatalogDAO 的公開方法返回的 Item,并指定序列化中應當包含 Item 的哪個成員。成員的指定采用 JavaBean 命名規范,所以 DWR 會調用對應的 get 方法。在這個示例中,我去掉了數字的 price 字段,而是包含了 formattedPrice 字段,它采用貨幣格式進行顯示。

    現在,我準備把 dwr.xml 部署到 Web 應用程序的 WEB-INF 目錄,在那里 DWR servlet 會讀取它。但是,在繼續之前,確保每件事都按照希望的那樣運行是個好主意。



    回頁首


    測試部署

    如果 DWRServletweb.xml 定義把 init-param debug 設置為 true,那么就啟用了 DWR 非常有幫助的測試模式。導航到 /{your-web-app}/dwr/ 會把 DWR 配置的要進行遠程的類列表顯示出來。在其中點擊,會進入指定類的狀態屏幕。CatalogDAO 的 DWR 測試頁如圖 2 所示。除了提供粘貼到 Web 頁面的 script 標記(指向 DWR 為類生成的 JavaScript)之外,這個屏幕還提供了類的方法列表。這個列表包括從類的超類繼承的方法,但是只有在 dwr.xml 中顯式地指定為遠程的才標記為可訪問。


    圖 2. CatalogDAO 的 DWR 測試頁
    DWR 為 CatalogDAO 生成的診斷和測試頁

    可以在可訪問的方法旁邊的文本框中輸入參數值并點擊 Execute 按鈕調用方法。服務器的響應將在警告框中用 JSON 標注顯示出來,如果是簡單值,就會內聯在方法旁邊直接顯示。這個測試頁非常有用。它們不僅允許檢查公開了哪個類和方法用于遠程,還可以測試每個方法是否像預期的那樣工作。

    如果對遠程方法的工作感到滿意,就可以用 DWR 生成的 JavaScript 存根從客戶端代碼調用服務器端對象。



    回頁首


    調用遠程對象

    遠程 Java 對象方法和對應的 JavaScript 存根函數之間的映射很簡單。通用的形式是 JavaScriptName.methodName(methodParams ..., callBack),其中 JavaScriptNamecreatorjavascript 屬性指定的名稱,methodParams 代表 Java 方法的 n 個參數,callback 是要用 Java 方法的返回值調用的 JavaScript 函數。如果熟悉 Ajax,可以看出這個回調機制是 XMLHttpRequest 異步性的常用方式。

    在示例場景中,我用清單 3 中的 JavaScript 函數執行搜索,并用搜索結果更新用戶界面。這個清單還使用來自 DWR 的 util.js 的便捷函數。要特別說明的是名為 $() 的 JavaScript 函數,可以把它當作 document.getElementById() 的加速版。錄入它當然更容易。如果您使用過 JavaScript 原型庫,應當熟悉這個函數。


    清單 3. 從客戶機調用遠程的 findItems()
    												
    														/*
     * Handles submission of the search form
     */
    function searchFormSubmitHandler() {
    
      // Obtain the search expression from the search field
      var searchexp = $("searchbox").value;
    
      // Call remoted DAO method, and specify callback function
      catalog.findItems(searchexp, displayItems);
    
      // Return false to suppress form submission
      return false;
    }
           
    /*
     * Displays a list of catalog items
     */
    function displayItems(items) {
    
      // Remove the currently displayed search results
      DWRUtil.removeAllRows("items");
    
      if (items.length == 0) {
        alert("No matching products found");
        $("catalog").style.visibility = "hidden";
      } else {
    
        DWRUtil.addRows("items",items,cellFunctions);
        $("catalog").style.visibility = "visible";
      }
    }
    												
    										

    在上面的 searchFormSubmitHandler() 函數中,我們感興趣的代碼當然是 catalog.findItems(searchexp, displayItems);。這一行代碼就是通過網絡向 DWR servlet 發送 XMLHttpRequest 并用遠程對象的響應調用 displayItems() 函數所需要的全部內容。

    displayItems() 回調本身是由一個 Item 數組表示調用的。這個數組傳遞給 DWRUtil.addRows() 便捷函數,同時還有要填充的表的 ID 和一個函數數組。表中每行有多少單元格,這個數組中就有多少個函數。按照順序使用來自數組的 Item 逐個調用每個函數,并用返回的內容填充對應的單元格。

    在這個示例中,我想讓商品表中的每一行都顯示商品的名稱、說明和價格,并在最后一列顯示商品的 Add to Cart 按鈕。清單 4 顯示了實現這一功能的單元格函數數組:


    清單 4. 填充商品表的單元格函數數組
    												
    														/*
     * Array of functions to populate a row of the items table
     * using DWRUtil′s addRows function
     */
    var cellFunctions = [
      function(item) { return item.name; },
      function(item) { return item.description; },
      function(item) { return item.formattedPrice; },
      function(item) {
        var btn = document.createElement("button");
        btn.innerHTML = "Add to cart";
        btn.itemId = item.id;
        btn.onclick = addToCartButtonHandler;
        return btn;
      }
    ];
    
    												
    										

    前三個函數只是返回 dwr.xml 中 Itemconvertor 包含的字段內容。最后一個函數創建一個按鈕,把 Item 的 ID 賦給它,并指定在點擊按鈕時應當調用名為 addToCartButtonHandler 的函數。這個函數是第二個用例的入口點:向購物車中添加 Item



    回頁首


    實現購物車

    DWR 的安全性

    DWR 設計時就考慮了安全性。使用 dwr.xml 明確地列出那些想做遠程處理的類和方法,可以避免意外地把那些可能被惡意利用的功能公開出去。除此之外,使用調試測試模式,可以容易地審計所有公開到 Web 上的類和方法。

    DWR 也支持基于角色的安全性。通過 bean 的 creator 配置,可以指定用戶訪問特定 bean 所必須屬于的 J2EE 角色。通過部署多個 URL 受保護的 DWRServlet 實例,每個實例都有自己的 dwr.xml 配置文件,也可以提供擁有不同遠程功能的用戶集。

    用戶購物車的 Java 表示基于 Map。當 Item 添加到購物車中時,Item 本身作為鍵被插入 MapMap 中對應的值是一個 Integer,代表購物車中指定 Item 的數量。所以 Cart.java 有一個字段 contents,聲明為 Map<Item,Integer>

    使用復雜類型作為哈希鍵給 DWR 帶來一個問題 —— 在 JavaScript 中,數組的鍵必須是標量的。所以,DWR 無法轉換 contents Map。但是,對于購物車用戶界面來說,用戶需要查看的只是每個商品的名稱和數量。所以我向 Cart 添加了一個名為 getSimpleContents() 的方法,它接受 contents Map 并根據它構建一個簡化的 Map<String,Integer>,只代表每個 Item 的名稱和數量。這個用字符串作為鍵的 map 表示可以由 DWR 的轉換器轉換成 JavaScript。

    客戶對 Cart 感興趣的其他字段是 totalPrice,它代表購物車中所有商品的金額匯總。使用 Item,我還提供了一個合成的成員叫作 formattedTotalPrice,它是金額匯總的格式化好的 String 表示。

    轉換購物車

    為了不讓客戶代碼對 Cart 做兩個調用(一個獲得內容,一個獲得總價),我想把這些數據一次全都發給客戶。為了做到這一點,我添加了一個看起來有點兒怪的方法,如清單 5 所示:


    清單 5. Cart.getCart() 方法
    												
    														/**
     * Returns the cart itself - for DWR
     * @return the cart
     */ 
    public Cart getCart() {
      return this;
    }
    
    												
    										

    雖然這個方法在普通的 Java 代碼中可能完全是多余的(因為在調用這個方法時,已經有對 Cart 的引用),但它允許 DWR 客戶讓 Cart 把自己序列化成 JavaScript。

    除了 getCart(),需要遠程化的另一個方法是 addItemToCart()。這個方法接受目錄 Item 的 ID 的 String 表示,把這個商品添加到 Cart 中并更新總價。方法還返回 Cart,這樣客戶代碼在一個操作中就能更新 Cart 的內容并接收購物車的新狀態。

    清單 6 是擴展的 dwr.xml 配置文件,包含 Cart 類進行遠程所需要的額外配置:


    清單 6. 修改過的 dwr.xml 包含了 Cart 類
    												
    														<!DOCTYPE dwr PUBLIC
        "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
        "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
    <dwr>
      </allow>
        </create creator="new" javascript="catalog">
          </param name="class" 
            value="developerworks.ajax.store.CatalogDAO"/>
          </include method="getItem"/>
          </include method="findItems"/>
        <//create>
        </convert converter="bean" 
          match="developerworks.ajax.store.Item">
          </param name="include" 
            value="id,name,description,formattedPrice"/>
        <//convert>
    														
    																
    																		    </create creator="new" scope="session" javascript="Cart">
          </param name="class" 
            value="developerworks.ajax.store.Cart"/>
          </include method="addItemToCart"/>
          </include method="getCart"/>
        <//create>
        </convert converter="bean" 
          match="developerworks.ajax.store.Cart">
          </param name="include" 
            value="simpleContents,formattedTotalPrice"/>
        <//convert>
    																
    														
    														  <//allow>
    </dwr>
    
    												
    										

    在這個版本的 dwr.xml 中,我添加了 Cartcreatorconvertorcreate 元素指定應當把 addItemToCart()getCart() 方法遠程化,而且重要的是,生成的 Cart 實例應當放在用戶的會話中。所以,購物車的內容在用戶的請求之間會保留。

    Cartconvert 元素是必需的,因為遠程的 Cart 方法返回的是 Cart 本身。在這里我指定在 Cart 的序列化 JavaScript 形式中應當存在的成員是 simpleContents 這個圖和 formattedTotalPrice 這個字符串。

    如果對這覺得有點兒不明白,那么只要記住 create 元素指定的是 DWR 客戶可以調用的 Cart 服務器端方法,而 convert 元素指定在 Cart 的 JavaScript 序列化形式中包含的成員。

    現在可以實現調用 Cart 的遠程方法的客戶端代碼了。



    回頁首


    調用遠程的 Cart 方法

    首先,當商店的 Web 頁首次裝入時,我想檢查保存在會話中的 Cart 的狀態,看是否已經有一個購物車了。這是必需的,因為用戶可能已經向 Cart 中添加了商品,然后刷新了頁面或者導航到其他地方之后又返回來。在這些情況下,重新載入的頁面需要用會話中的 Cart 數據對自己進行同步。我可以在頁面的 onload 函數中用一個調用做到這一點,就像這樣:Cart.getCart(displayCart)。請注意 displayCart() 是一個回調函數,由服務器返回的 Cart 響應數據調用。

    如果 Cart 已經在會話中,那么creator 會檢索它并調用它的 getCart() 方法。如果會話中沒有 Cart,那么 creator 會實例化一個新的,把它放在會話中,并調用 getCart() 方法。

    清單 7 顯示了 addToCartButtonHandler() 函數的實現,當點擊商品的 Add to Cart 按鈕時會調用這個函數:


    清單 7. addToCartButtonHandler() 實現
    												
    														/*
     * Handles a click on an Item′s "Add to Cart" button
     */
    function addToCartButtonHandler() {
    
      // ′this′ is the button that was clicked.
      // Obtain the item ID that was set on it, and
      // add to the cart.
      Cart.addItemToCart(this.itemId,displayCart);
    }
    
    												
    										

    由 DWR 負責所有通信,所以客戶上的添加到購物車行為就是一個函數。清單 8 顯示了這個示例的最后一部分 —— displayCart() 回調的實現,它用 Cart 的狀態更新用戶界面:


    清單 8. displayCart() 實現
    												
    														/*
     * Displays the contents of the user′s shopping cart
     */
    function displayCart(cart) {
    
      // Clear existing content of cart UI
      var contentsUL = $("contents");
      contentsUL.innerHTML="";
    
      // Loop over cart items
      for (var item in cart.simpleContents) {
    
        // Add a list element with the name and quantity of item
        var li = document.createElement("li");
        li.appendChild(document.createTextNode(
                        cart.simpleContents[item] + " x " + item
                      ));
        contentsUL.appendChild(li);
      }
    
      // Update cart total
      var totalSpan = $("totalprice");
      totalSpan.innerHTML = cart.formattedTotalPrice;
    }
    
    												
    										

    在這里重要的是要記住,simpleContents 是一個把 String 映射到數字的 JavaScript 數組。每個字符串都是一個商品的名稱,關聯數組中的對應數字就是購物車中該商品的數量。所以表達式 cart.simpleContents[item] + " x " + item 可能就會計算出 “2 x Oolong 128MB CF Card” 這樣的結果。

    DWR 商店應用程序

    圖 3 顯示了這個基于 DWR 的 Ajax 應用程序的使用情況:顯示了通過搜索檢索到的商品,并在右側顯示用戶的購物車:


    圖 3. 基于 DWR 的 Ajax 商店應用程序的使用情況
    示例場景的截屏,帶有搜索結果和購物車


    回頁首


    DWR 的利弊

    調用批處理

    在 DWR 中,可以在一個 HTTP 請求中向服務器發送多個遠程調用。調用 DWREngine.beginBatch() 告訴 DWR 不要直接分派后續的遠程調用,而是把它們組合到一個批請求中。DWREngine.endBatch() 調用則把批請求發送到服務器。遠程調用在服務器端順序執行,然后調用每個 JavaScript 回調。

    批處理在兩方面有助于降低延遲:第一,避免了為每個調用創建 XMLHttpRequest 對象并建立相關的 HTTP 連接的開銷。第二,在生產環境中,Web 服務器不必處理過多的并發 HTTP 請求,改進了響應時間。

    現在可以看出用 DWR 實現由 Java 支持的 Ajax 應用程序有多么容易了。雖然示例場景很簡單,我實現用例的手段也盡可能少,但是不應因此而低估 DWR 引擎相對于自己設計 Ajax 應用程序可以節約的工作量。在前一篇文章中,我介紹了手工設計 Ajax 請求和響應、把 Java 對象圖轉化成 JSON 表示的全部步驟,在這篇文章中,DWR 替我做了所有這些工作。我只編寫了不到 50 行 JavaScript 就實現了客戶機,而在服務器端,我需要做的所有工作就是給常規的 JavaBean 加上一些額外方法。

    當然,每種技術都有它的不足。同任何 RPC 機制一樣,在 DWR 中,可能很容易忘記對于遠程對象進行的每個調用都要比本地函數調用昂貴得多。DWR 在隱藏 Ajax 的機械性方面做得很好,但是重要的是要記住網絡并不是透明的 —— 進行 DWR 調用會有延遲,所以應用程序的架構應當讓遠程方法的粒度比較粗。正是為了這個目的,addItemToCart() 才返回 Cart 本身。雖然讓 addItemToCart() 作為一個 void 方法可能更自然,但是這樣的話對它的每個 DWR 調用后面都必須跟著一個 getCart() 調用以檢索修改后的 Cart 狀態。

    對于延遲,DWR 在調用的批處理中有自己的解決方案(請參閱側欄的 調用批處理 )。如果不能為應用程序提供適當粗粒度的 Ajax 接口,那么只要有可能把多個遠程調用組合到一個 HTTP 請求中,就請使用調用批處理。

    分離的問題

    從實質上看,DWR 在客戶端和服務器端代碼間形成了緊密的耦合,這有許多含義:首先,遠程方法 API 的變化需要在 DWR 存根調用的 JavaScript 上反映出來。第二(也是最明顯的),這種耦合會造成對客戶端的考慮會滲入服務器端代碼。例如,因為不是所有 Java 類型都能轉化成 JavaScript,所以有時有必要給 Java 對象添加額外方法,好讓它能夠更容易地遠程化。在示例場景中,我通過把 getSimpleContents() 方法添加到 Cart 來解決這個問題。我還添加了 getCart() 方法,它在 DWR 場景中是有用的,但在其他場景中則完全是多余的。由于遠程對象粗粒度 API 的需要以及把某些 Java 類型轉化成 JavaScript 的問題,所以可以看到遠程 JavaBean 會被那些只對 Ajax 客戶有用的方法“污染”。

    為了克服這個問題,可以使用包裝器類把額外的特定于 DWR 的方法添加到普通 JavaBean。這意味著 JavaBean 類的 Java 客戶可能看不到與遠程相關聯的額外的毛病,而且也允許給遠程方法提供更友好的名稱 —— 例如用 getPrice() 代替 getFormattedPrice()。圖 4 顯示的 RemoteCart 類對 Cart 進行了包裝,添加了額外的 DWR 功能:


    圖 4. RemoteCart 為遠程功能對 Cart 做了包裝
    RemoteCart 包裝器類的類圖

    最后,需要記住:DWR Ajax 調用是異步的,所以不要期望它們會按照分派的順序返回。在示例代碼中我忽略了這個小問題,但是在這個系列的第一篇文章中,我演示了如何為響應加時間戳,以此作為保證數據到達順序的一種簡單手段。



    回頁首


    結束語

    正如所看到的,DWR 提供了許多東西 —— 它允許迅速而簡單地創建到服務器端域對象的 Ajax 接口,而不需要編寫任何 servlet 代碼、對象序列化代碼或客戶端 XMLHttpRequest 代碼。使用 DWR 部署到 Web 應用程序極為簡單,而且 DWR 的安全性特性可以與 J2EE 基于角色的驗證系統集成。但是 DWR 并不是對于任何一種應用程序架構都適合,所以在設計域對象的 API 時需要做些考慮。

    如果想學習用 DWR 進行 Ajax 的利弊的更多內容,最好的方式就是下載并開始實踐。DWR 有許多我沒有介紹的特性, 文章源代碼 是把 DWR 投入使用的一個良好起點。請參閱 參考資料 ,學習關于 Ajax、DWR 和相關技術的更多內容。

    這個系列中要指出的最重要的一點是:對于 Ajax 應用程序,沒有包治百病的解決方案。Ajax 是一個快速發展的領域,不斷有新技術涌現。在這個系列的三篇文章中,我的重點在于帶您開始在 Ajax 應用程序的 Web 層中利用 Java 技術 —— 不管是選擇基于 XMLHttpRequest 的帶有對象序列化框架的技術,還是選擇 DWR 這樣的更高級抽象。請在后續幾個月中留意面向 Java 開發人員介紹 Ajax 的文章。

    下載

    描述 名字 大小 ?下載方法
    DWR source code j-ajax3dwr.zip 301 KB ? FTP
    關于下載方法的信息 獲取 Adobe? Reader?


    回頁首


    參考資料

    學習



    凡是有該標志的文章,都是該blog博主Caoer(草兒)原創,凡是索引、收藏
    、轉載請注明來處和原文作者。非常感謝。

    posted on 2006-06-24 14:14 草兒 閱讀(1189) 評論(0)  編輯  收藏 所屬分類: Java編程經驗談ajax
    主站蜘蛛池模板: 在线免费观看一级毛片| 亚洲乱亚洲乱妇无码| 亚洲福利在线播放| 日本zzzzwww大片免费| a级毛片免费观看视频| 免费观看亚洲人成网站| 亚洲综合小说另类图片动图| 亚洲天天在线日亚洲洲精| 亚洲欧洲自拍拍偷精品 美利坚| 国产美女在线精品免费观看| 99re这里有免费视频精品| 免费无码H肉动漫在线观看麻豆| 精品亚洲视频在线| 亚洲欧美精品午睡沙发| 亚洲国产精品综合一区在线| 亚洲人成在线观看| 亚洲av无码成人黄网站在线观看 | 亚洲熟妇无码八AV在线播放| 日韩精品电影一区亚洲| 国产午夜无码视频免费网站| 国内精品免费视频自在线| 最近最新中文字幕完整版免费高清| 91九色视频无限观看免费| 91福利免费体验区观看区| 久久久久成人精品免费播放动漫| 手机看片国产免费永久| 国产一区二区三区免费观在线| caoporm超免费公开视频| 2022免费国产精品福利在线| 丰满少妇作爱视频免费观看| 日本免费精品一区二区三区 | 免费国产综合视频在线看| 日韩特黄特色大片免费视频| 免费观看一级毛片| 国产免费无遮挡精品视频| 免费a级毛片无码a∨性按摩| 免费va在线观看| 亚洲精品无码av天堂| 国产亚洲精品精品国产亚洲综合| 亚洲中文字幕无码一区二区三区| 亚洲精品无码专区在线在线播放 |