先說說注釋語法,省掉dwr.xml。(自從用了java 5 之後,現在越看一堆堆的配置文件越煩,越來越喜歡注釋方式來的直接簡單了)
首先下載最新的穩定版本的dwr.jar文件放到你的工程中。(還有需要其它的嗎?不需要了,dwr就是這麼簡單)
然後在web.xml中添加如下一段
<!-- DWRServlet -->
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<!-- 默認為false,調試用,可以訪問http://地址:端口/上下文/dwr 來進行測試 -->
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<!--這就是傳說中的DWR反轉調用的開關了,默認也是false -->
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<!--日志級別不多說了-->
<init-param>
<param-name>logLevel</param-name>
<param-value>WARN</param-value>
</init-param>
<!--這塊注意了,關鍵來了,把使用DWR注釋的類都要加在這裡,2.0的DWR好像還不支持包掃描,希望以後能提供這個功能,3.0我還沒注意有沒有這個功能,現在還沒出正式版-->
<init-param>
<param-name>classes</param-name>
<param-value>
org.relax.service.SectionManager,
org.relax.service..entity.Section
</param-value>
</init-param>
</servlet>
<!--這塊不用多說了吧,如果看不懂,哪涼快哪呆著去吧-->
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
在這裡再說明一下有的文章用的是uk.ltd.getahead.dwr.DWRServlet,其實他只是繼承了一下 org.directwebremoting.servlet.DwrServlet自己什麼也沒做,所以這兩個類用哪個都行(這麼做應該是為了兼容以前的版本,猜的,1.0我沒用過)。
下面看具體的類吧。
@Service
@RemoteProxy(creator = SpringCreator.class, name = "sectionManager", creatorParams = @Param(name = "beanName", value = "sectionManager"))
public class SectionManager extends DefaultEntityManager<Section, Integer> {
@Autowired
OriginCollectDataManager originCollectDataManager;
@RemoteMethod
public Section get(Integer id) {
return super.get(id);
}
@RemoteMethod
public List<Section> getAll() {
return super.getAll();
}
}
我的測試環境裡還用到了spring和hibernate,所以裡面還摻雜了一些spring的注釋標記,當然如果你沒用也無所謂。
這裡主要解釋一下DWR的幾個Annotations
@RemoteProxy標在類上的就是使類可以運程訪問
@RemoteProxy(creator = SpringCreator.class, name = "sectionManager", creatorParams = @Param(name = "beanName", value = "sectionManager")),
上面因為使用了spring所以寫的是springCreator.class, 其它還有BeanCreator, Ejb3Creator, JsfCreator, NewCreator, NullCreator, PageFlowCreator, ScriptedCreator, SingletonCreator, SpringCreator, StrutsCreator。看自己的具體需求。最常用的就是newCreator了吧。
@RemoteMethod標在方法上,不用多說可以使方法能遠程訪問
@DataTransferObject標在類上,注明需要轉換的VO類了
@RemoteProperty標在類的屬性上,標明哪些可以訪問(我試了試不標,好像全都可以訪問了)
常用的就這麼多了,其它幾個不太常用,如果用到的時候再研究吧。
還有什麼要做的嗎?好像就這麼多了。DWR就是簡單。如果標好了可以試試訪問上下文路徑加上/dwr來訪問試試了。好像好用了哎。如下圖
點進去看看都有什麼方法
看上去方法好像挺多,其實真正能訪問用的只有用@RemoteMethod標注過的。
測試已經好用了下面就是加到頁面了。那不就更簡單了嗎。按著上圖收到JSP文件中。然後像調用普通javascript對象一樣就可以了。咱不是做普及的,今天主要講注釋的用法。這部分就到這吧。
下面說反向調用了,這個還是挺復雜的,首先解釋幾個概念。
dwr的逆向ajax其實主要包括兩種模式:主動模式和被動模式。其中主動模式包括Polling和Comet兩種,被動模式只有Piggyback這一種。
所謂的Piggyback指的是如果後台有什麼內容需要推送到前台(即調用頁面的js方法),是要等到那個頁面進行下一次ajax請求的時候,將需要推送的內容附加在該次請求之後,傳回到頁面。
polling指的是由浏覽器定時向服務端發送ajax請求,詢問後台是否有什麼內容需要推送,有的話就會由服務端返回推送內容。這種方式和我們直接在頁面通過定時器發送ajax請求,然後查詢後台是否有變化內容的實現是類似的。只不過用了dwr之後這部分工作由框架幫我們完成了。
comet模式指的的當服務端建立和浏覽器的連接,將頁面內容發送到浏覽器之後,對應的連接並不關閉,只是暫時掛起。如果後面有什麼新的內容需要推送到客戶端的時候直接通過前面掛起的連接再次傳送數據。
通過上面的解釋我們可以看到,這三種模式都有各自的優缺點。從客戶端請求次數的角度來說,當然是piggyback的模式最好。這個裡面完全沒有額外的網絡請求,只有等到下次請求頁面主動發起了,中間的變化內容才傳遞回頁面。但是這也導致了這推送內容的延時,因為你完全沒辦法知道頁面的下一次請求將在什麼時候發起,也許頁面永遠都沒有下一次請求。polling模式的網絡請求最為頻繁了,因為這時候頁面不管後台有沒有更新的內容,都需要發送請求詢問。雖然這種模式可以通過增加請求間隔的時間來減少單位時間內的請求次數,但是這樣同樣會導致頁面響應後台內容變化的間隔時間增長,這中間就產生了矛盾,具體的請求間隔時間還是要根據具體項目的需求來配置。比如服務器能承受的請求間隔和頁面內容所需要的刷新頻率。comet方式的響應速度應該是最快的,後台一旦有內容需要推送可以通過前面沒有關閉的連接馬上推送到前台。但是服務器所能提供的連接數目是一定的,在大量的掛起的連接沒有關閉的情況下,可能造成新的連接請求不能接入,從而影響到服務質量。
以上摘自dwr的Reverse Ajax(推技術的實現之一)
概念說清楚了,下面做一吧。
前面已經說完了注釋方式了,以下還用注釋的方式,方便直觀呀。
@RemoteMethod
public synchronized void start() {
WebContext wctx = WebContextFactory.get();
String currentPage = wctx.getCurrentPage();
running=true;
for (int i = 0; i < 1000; i++) {
if (!running) {
break;
}
ScriptBuffer script = new ScriptBuffer();
script.appendScript("receiveMessages(").appendData(i).appendScript(");");//調用頁面的javascript方法把值添到頁面上。
// Loop over all the users on the current page
Collection pages = wctx.getScriptSessionsByPage(currentPage);//循環出所有的會話頁面並執行
for (Iterator it = pages.iterator(); it.hasNext();) {
System.err.println(i);
ScriptSession otherSession = (ScriptSession) it.next();
otherSession.addScript(script);
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@RemoteMethod
public void stop() {
running=false;
}
這是個簡單的程序進行之後就是用個循環來更新頁面的數字。
下面也貼一下JSP的代碼吧。也算補充下第一部分了。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script type='text/javascript' src='/dymc-web/dwr/interface/sectionManager.js'></script>
<script type='text/javascript' src='/dymc-web/dwr/engine.js'></script>
<script type="text/javascript">
function receiveMessages(msg) {
//alert(msg);
document.getElementById("content").innerHTML=msg;
}
</script>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body onload="dwr.engine.setActiveReverseAjax(true)">
<button onclick="sectionManager.start()">start</button>
<button onclick="sectionManager.stop()">stop</button>
<div id="content"></div>
</body>
</html>
頁面包括兩個鈕一個開始一個停止。大家來試試吧。這裡不添圖了太浪費空間
運行起來後點start按鈕,看看頁面上是不是自己開始變了。新打開個IE,用另外的機器訪問此面,疑?怎麼都有數字在變換,這就是DWR Reverse Ajax的厲害所在了。再點一下stop,呀,所有打個IE裡數字都不變了吧。
注意:代碼用的是主動的方式,所以注意頁面onload中的<body onload="dwr.engine.setActiveReverseAjax(true)">沒有這句可就不好用了。當然 web.xml中也不能少了
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
該說的都說了就到這吧。