DWR詳解(二)——反向AJAX

來源:互聯網
上載者:User

上一篇文章(DWR詳解一)提到DWR允許javascript訪問伺服器端的Java方法,這使得AJAX使用起來會比較容易,而在DWR2.0裡面添加了一個非常強大的功能——反向AJAX,也就是說,伺服器端的Java方法可以取得瀏覽器端的Web上下文,並可以調用javascript的方法,將伺服器端的資料非同步地傳輸給瀏覽器。本文將通過一個demo展示這種特性。這個demo實現了類似股票交易系統中即時更新資料的功能,事實上是通過發布-訂閱模式去實現的。也就是說,客訂閱一個主題,伺服器端通過一個線程向訂閱這個主題的瀏覽器定時、非同步地發送資料,從而實現了這種即時更新的功能。工程代碼請點擊這裡下載reverseAjaxDemo

    我們知道,用戶端瀏覽器可以隨時串連到web伺服器,並向伺服器請求資源,而伺服器卻沒有這種能力,它不能主動地於用戶端瀏覽器建立串連,並主動地將資料發送給瀏覽器。DWR支援3種從伺服器端發送資料給用戶端的方式:

1、輪詢。用戶端在每個時間周期內向伺服器發送請求,看看伺服器端有沒有資料更新,如果有,就向伺服器請求資料。

2、Comet:基於HTTP長已連線的服務器推動方式。用戶端向伺服器發送請求後,伺服器將資料通過response發送給用戶端,但並不會將此response關閉,而是一直通過response將最新的資料發送給用戶端瀏覽器,直到用戶端瀏覽器關閉。

3、PiggyBack(回傳)。伺服器端將最新的資料排成隊列,然後等待用戶端下一次請求,接收到請求後就將等待更新的資料發給用戶端。

這3種方式各有優劣,而DWR可以同時支援輪詢和Comet。

首先,我們要讓DWR程式支援反向AJAX。只需要在web.xml中DWRServlet裡添加一個初始化參數:

<servlet><servlet-name>dwr-invoker</servlet-name><servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class><init-param><param-name>activeReverseAjaxEnabled</param-name><param-value>true</param-value></init-param>...</servlet>

另外,這個demo使用了TIBCO General Interface(GI)的AJAX架構,因此需要引入JSX這個組件庫以及在gidemo目錄下在config.xml和appCanvas.xml定義需要使用的組件(主要是用到Matrix資料表格這個組件),關於TIBCO GI,請參考http://www.tibco.com/devnet/index.html

這個demo的核心之處在於伺服器端的發行者——Publisher.java,在這個類裡面,首先通過org.directwebremoting.WebContext來獲得訪問這個應用的Web上下文:

WebContext webContext = WebContextFactory.get();
ServletContext servletContext = webContext.getServletContext();
serverContext = ServerContextFactory.get(servletContext);

webContext.getScriptSessionsByPage("");

這裡主要通過WebContext類獲得DWR應用的WEB上下文,用ServletContext獲得DWRServlet的上下文,以及通過WEB上下文擷取訪問本應用的用戶端瀏覽器的ScriptSession。通過ScriptSession,可以在伺服器端向用戶端瀏覽器發出執行js方法的指令,並把伺服器端資料傳送給js方法,具體的用法如下:

Collection sessions = serverContext.getScriptSessionsByPage("/reverseAjaxDemo/index.html");
ScriptProxy proxy = new ScriptProxy(sessions);
Corporation corp = corporations.getNextChangedCorporation();
proxy.addFunctionCall("OpenAjax.publish", "gidemo", "corporation", corp);

這段代碼首先通過getScriptSessionsByPage方法獲得所有訪問/reverseAjaxDemo/index.html這個資源的用戶端瀏覽器的ScriptSession,並為這些session建立代理(ScriptProxy),通過這個代理,讓用戶端執行OpenAjax.publish的js方法(見OpenAjax.js)。其中addFunctionCall就是向用戶端發送執行js方法的伺服器端方法,第一個參數是js方法的簽名,後面的都是js方法的參數。其中"gidemo"是伺服器端發布的主題(topic),"coporation"是要發布的變數,而corp則是要發布的即時資料。corp這個對象是隨機產生的(見Corporation和Corporations類),Publish.java這個類啟動了一個線程(worker),這個線程不斷地產生corporation的資料,並發布給用戶端。

以下是html頁面的核心部分的代碼:

<div style="width:100%; height:280px;" id="gidemo">
      <script. type="text/javascript"
              src="JSX/js/JSX30.js"
              jsxapppath="gidemo"
               jsxlt="true"> </script>
</div>

這一塊代碼主要是使用了GI的matrix組件,該組件可以動態載入資料。另外,頁面引入了index.js,裡面有兩個個主要方法:

function giLoaded() {
  OpenAjax.subscribe("gidemo", "corporation", objectPublished);
  dwr.engine.setActiveReverseAjax(true);
}

function objectPublished(prefix, name, handlerData, corporation) {
  var matrix = giApp.getJSXByName("matrix");
  var inserted = matrix.getRecordNode(corporation.jsxid);
  matrix.insertRecord(corporation, null, inserted == null);

  // There are many ways to get a table to repaint.
  // One easy way is to ask it to repaint:
  // matrix.repaintData();

  // But we are going for a fancy option that does highlighting
  for (var property in corporation) {
    if (property != "jsxid") {
      var x = matrix.getContentElement(corporation.jsxid, property);
      if (ox) {
        var current = ox.innerHTML;
        if (current != "" + corporation[property]) {
          ox.style.backgroundColor = "#FDE4EB";
          var callback = function(ele) {
            return function() { ele.style.backgroundColor = "#FFFFFF"; };
          }(ox);
          setTimeout(callback, 1000);
          ox.innerHTML = corporation[property];
        }
      }
    }
  }
}

giLoaded方法通過OpenAjax.subscribe方法訂閱主題為"gidemo"的資料(這些資料由伺服器端的Java方法進行發布)。其中objectPublished是一個回調方法,表示取得資料後頁面的改變。該回調方法非常簡單,只是將matrix組件中發生變化的資料改變一下顏色,實現了即時提醒資料更新的功能。

另外,伺服器端還有一個監聽器PublisherServletContextListener,這是為了在適當的時候關閉發行者的線程。這個監聽器要結合其他兩個DWR的監聽器使用,只需在web.xml裡面聲明就行了:

<listener>
     <listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextAttributeListener</listener-class>
</listener>
<listener>
        <listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>gidemo.PublisherServletContextListener</listener-class>
    </listener>

最後,看一下dwr的映射關係dwr.xml:

<dwr>
  <allow>
    <create creator="new" javascript="JDate">
      <param name="class" value="java.util.Date"/>
    </create>
    <create creator="new" javascript="Publisher" scope="application">
      <param name="class" value="gidemo.Publisher"/>
    </create>
   <convert converter="bean" match="gidemo.Corporation"/>

    <!-- this is a bad idea for live, but can be useful in testing -->
    <convert converter="exception" match="java.lang.Exception"/>
    <convert converter="bean" match="java.lang.StackTraceElement"/>
  </allow>
</dwr>

注意紅色部分的配置,dwr允許將自訂的Java類型與js對象進行相互轉換,但要聲明轉換器。

以下是程式啟動並執行結果:

這個例子比較複雜,旨在讓大家對反向AJAX的原理有所瞭解。下一篇文章開始,將用一些簡單的例子來說明DWR反向AJAX的用法。

參考資料:

http://getahead.org/dwr/reverse-ajax

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.