Dwr的逆向ajax其實主要包括兩種模式:主動模式和被動模式。其中主動模式包括Polling和Comet兩種,被動模式只有Piggyback這一種。
所謂的Piggyback指的是如果後台有什麼內容需要推送到前台(即調用頁面的js方法),是要等到那個頁面進行下一次ajax請求的時候,將需要推送的內容附加在該次請求之後,傳回到頁面。
polling指的是由瀏覽器定時向服務端發送ajax請求,詢問後台是否有什麼內容需要推送,有的話就會由服務端返回推送內容。這種方式和我們直接在頁面通過定時器發送ajax請求,然後查詢後台是否有變化內容的實現是類似的。只不過用了Dwr之後這部分工作由架構幫我們完成了。
comet模式指的的當服務端建立和瀏覽器的串連,將頁面內容發送到瀏覽器之後,對應的串連並不關閉,只是暫時掛起。如果後面有什麼新的內容需要推送到用戶端的時候直接通過前面掛起的串連再次傳送資料。
通過上面的解釋我們可以看到,這三種模式都有各自的優缺點。從用戶端請求次數的角度來說,當然是piggyback的模式最好。這個裡面完全沒有額外的網路請求,只有等到下次請求頁面主動發起了,中間的變化內容才傳遞迴頁面。但是這也導致了這推送內容的延時,因為你完全沒辦法知道頁面的下一次請求將在什麼時候發起,也許頁面永遠都沒有下一次請求。polling模式的網路請求最為頻繁了,因為這時候頁面不管後台有沒有更新的內容,都需要發送請求詢問。雖然這種模式可以通過增加請求間隔的時間來減少單位時間內的請求次數,但是這樣同樣會導致頁面響應後台內容變化的間隔時間增長,這中間就產生了矛盾,具體的請求間隔時間還是要根據具體項目的需求來配置。比如伺服器能承受的請求間隔和頁面內容所需要的重新整理頻率。comet方式的響應速度應該是最快的,後台一旦有內容需要推送可以通過前面沒有關閉的串連馬上推送到前台。但是伺服器所能提供的串連數目是一定的,在大量的掛起的串連沒有關閉的情況下,可能造成新的串連請求不能接入,從而影響到服務品質。
一、配置情況
1)、piggyback方式
Dwr預設採用的是piggyback這種被動模式,如果需要採用這種模式的話不需要任何額外的配置就能完成。
2)、comet方式
如果需要採用主動模式的話就需要進行一些相應的配置了,首先需要在web.xml中dwr的servlet中配置如下的參數:
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
在需要接受推送內容的頁面body的onload事件中需要調用:
dwr.engine.setActiveReverseAjax(true);
方法來啟動該頁面的ReverseAjax功能。這時候預設採用的將是comet的方式來完成頁面內容的推送。
3)、polling方式
如果想採用polling方式,只需要在comet方式的基礎之上,在servlet參數中再加上如下的參數:
<init-param>
<param-name>org.directwebremoting.extend.ServerLoadMonitor</param-name>
<param-value>org.directwebremoting.impl.PollingServerLoadMonitor</param-value>
</init-param>
其中頁面預設的請求間隔時間是5秒,如果需要進行配置的話通過如下的參數來完成:
<init-param>
<param-name>disconnectedTime</param-name>
<param-value>60000</param-value>
</init-param>
說明:這就將請求間隔時間設為了60秒。
二、調用方式
後台可以通過如下的方式來推送內容:
ScriptBuffer script = new ScriptBuffer();
script.appendScript("這裡加入需要頁面執行的js代碼的字串");
ServerContext sctx = ServerContextFactory.get(servletContext);
if (sctx != null)
{
Collection pages = sctx.getScriptSessionsByPage("這裡加入待推送頁面的相對路徑,例如/book/list.jsp");
Iterator it = pages.iterator();
While (it.hasNext())
{
ScriptSession session = (ScriptSession)it.next();
session.addScript(script);
}
}
其中的servletContext可以既可以是通過前台請求傳入的,也可以是通過該類實現spring的ServletContextAware介面,由spirng注入的。並且在調用ServerContextFactory.get(servletContext)方法之前,Dwr的上下文已經建立起來了。
在完成了以上工作之後就可以享受到dwr通過Reverse Ajax給你帶來的驚喜體驗了,你可以像cs模式中server直接操作client那樣便利的操作browser了。
三、實現方式
模擬我前面寫的<<最簡單的DWR例子>>內容,建立web project工程testAjax。本常式主要實現伺服器主動重新整理用戶端頁面內的目前時間,在編輯框內產生隨機數。
1)、Clock.java代碼
package com.test.ajax; import org.directwebremoting.ServerContextFactory;import org.directwebremoting.Browser;import org.directwebremoting.ui.dwr.Util; import java.util.Date;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit; publicclass Clock implements Runnable { protectedtransientbooleanactive = false; inti = 0; public Clock() { ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); executor.scheduleAtFixedRate(this, 1, 1, TimeUnit.SECONDS); } publicvoid run() { if (active) { setClockDisplay((new java.text.SimpleDateFormat("yyyy年MM月dd日 hh時mm分ss秒")).format(new Date())); } } /** * Called from the client to turn the clock on/off */ publicsynchronizedvoid toggle() { i++; active = !active; System.out.println("toggle clicked!" + i); System.out.println("active:" + active); if (active) { setClockDisplay("Started"); } else { setClockDisplay("Stopped"); } } publicvoid setClockDisplay(final String output) { String page = ServerContextFactory.get().getContextPath() + "/index.jsp"; Browser.withPage(page, new Runnable() { publicvoid run() { Util.setValue("clockDisplay", output); double dValue = Math.random(); String strValue = String.valueOf(dValue); Util.setValue("PointValue", strValue); } }); } }
2)、dwr.xml代碼
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd"> <dwr><allow><create creator="new" javascript="Clock" scope="application"><param name="class" value="com.test.ajax.Clock"/></create></allow></dwr>
3)、dwr.xml代碼
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> <init-param> <description>是否啟用反向Ajax</description> <param-name>activeReverseAjaxEnabled</param-name> <param-value>true</param-value> </init-param> <init-param> <description>在WEB啟動時是否建立範圍為application的creator</description> <param-name>initApplicationScopeCreatorsAtStartup</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
4)、index.jsp代碼
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><% String path = request.getContextPath();%><meta http-equiv="Content-Type" content="text/html; charset=GB18030"><title>Server-side clock</title><script type='text/javascript' src='dwr/engine.js'></script><script type='text/javascript' src='dwr/util.js'></script><script type='text/javascript' src='dwr/interface/Clock.js'></script><script language="javascript"> function Init() { dwr.engine.setActiveReverseAjax(true); }</script> </head> <body onload="Init()">點擊查看伺服器時間 <input type="button" value="Start/Stop" onclick="Clock.toggle();"/><br><br><h2 id="clockDisplay"></h2><input type="text" name="PointValue"></body> </html>
5)、
圖3-1 初始頁面
圖3-2 動態重新整理資料圖
四、未來用途
正常情況下,DWR 調用伺服器端的JavaBean 對象方法使用正向請求/響應模式, 也稱為拉模式(Pull Model) ,由用戶端JavaScript 調用JavaBean 方法, 返回結果通過回調方法更新頁面上的HTML 元素,實現監控資料的顯示。這種正向模式符合一般的管理系統應用, 但對監控系統即時性要求較高的應用卻力不從心。而反向模式即推模式(Push Model) , 是適應監控系統的最佳方式, 由伺服器組件將取得的監控資料推送到Web
用戶端,不需要用戶端主動請求, 而是被動接收。因而無需進行Web層進行頁面重新整理, 即可實現資料更新顯示。
圖4-1 典型監控WEB流程架構圖
完