DWR的注釋(annotations)使用及反向調(diào)用(Reverse Ajax)
最近也不是很忙花了點(diǎn)時(shí)間再仔細(xì)研究了一下DWR,其實(shí)兩三年前就已經(jīng)開(kāi)始使用它了。不過(guò)一直用的也比較簡(jiǎn)單DWR,沒(méi)花過(guò)太多的心思在上面(呵呵,主要還是項(xiàng)目沒(méi)需求啊)。不用再多說(shuō)了,相信大家都知道,配置和使用都非常簡(jiǎn)單。今天要說(shuō)的是DWR的一些高級(jí)一點(diǎn)用法。當(dāng)然也不難。只是為了防止自己忘記,同時(shí)也和其他人分享一下。 言歸正傳開(kāi)始吧。
先說(shuō)說(shuō)注釋語(yǔ)法,省掉dwr.xml。(自從用了java 5 之后,現(xiàn)在越看一堆堆的配置文件越煩,越來(lái)越喜歡注釋方式來(lái)的直接簡(jiǎn)單了)
首先下載最新的穩(wěn)定版本的dwr.jar文件放到你的工程中。(還有需要其它的嗎?不需要了,dwr就是這么簡(jiǎn)單)
然后在web.xml中添加如下一段
<!-- DWRServlet -->
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<!-- 默認(rèn)為false,調(diào)試用,可以訪問(wèn)http://地址:端口/上下文/dwr 來(lái)進(jìn)行測(cè)試 -->
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<!--這就是傳說(shuō)中的DWR反轉(zhuǎn)調(diào)用的開(kāi)關(guān)了,默認(rèn)也是false -->
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<!--日志級(jí)別不多說(shuō)了-->
<init-param>
<param-name>logLevel</param-name>
<param-value>WARN</param-value>
</init-param>
<!--這塊注意了,關(guān)鍵來(lái)了,把使用DWR注釋的類都要加在這里,2.0的DWR好像還不支持包掃描,希望以后能提供這個(gè)功能,3.0我還沒(méi)注意有沒(méi)有這個(gè)功能,現(xiàn)在還沒(méi)出正式版-->
<init-param>
<param-name>classes</param-name>
<param-value>
org.relax.service.SectionManager,
org.relax.service..entity.Section
</param-value>
</init-param>
</servlet>
<!--這塊不用多說(shuō)了吧,如果看不懂,哪涼快哪呆著去吧-->
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
在這里再說(shuō)明一下有的文章用的是uk.ltd.getahead.dwr.DWRServlet,其實(shí)他只是繼承了一下org.directwebremoting.servlet.DwrServlet自己什么也沒(méi)做,所以這兩個(gè)類用哪個(gè)都行(這么做應(yīng)該是為了兼容以前的版本,猜的,1.0我沒(méi)用過(guò))。
下面看具體的類吧。
@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();
}
}
我的測(cè)試環(huán)境里還用到了spring和hibernate,所以里面還摻雜了一些spring的注釋標(biāo)記,當(dāng)然如果你沒(méi)用也無(wú)所謂。這里主要解釋一下DWR的幾個(gè)Annotations
@RemoteProxy標(biāo)在類上的就是使類可以運(yùn)程訪問(wèn)
@RemoteProxy(creator = SpringCreator.class, name = "sectionManager", creatorParams = @Param(name = "beanName", value = "sectionManager")),
上面因?yàn)槭褂昧藄pring所以寫的是springCreator.class, 其它還有BeanCreator, Ejb3Creator, JsfCreator, NewCreator, NullCreator, PageFlowCreator, ScriptedCreator, SingletonCreator, SpringCreator, StrutsCreator。看自己的具體需求。最常用的就是newCreator了吧。
@RemoteMethod標(biāo)在方法上,不用多說(shuō)可以使方法能遠(yuǎn)程訪問(wèn)
@DataTransferObject標(biāo)在類上,注明需要轉(zhuǎn)換的VO類了
@RemoteProperty標(biāo)在類的屬性上,標(biāo)明哪些可以訪問(wèn)(我試了試不標(biāo),好像全都可以訪問(wèn)了)
常用的就這么多了,其它幾個(gè)不太常用,如果用到的時(shí)候再研究吧。
還有什么要做的嗎?好像就這么多了。DWR就是簡(jiǎn)單。如果標(biāo)好了可以試試訪問(wèn)上下文路徑加上/dwr來(lái)訪問(wèn)試試了。好像好用了哎。如下圖
點(diǎn)進(jìn)去看看都有什么方法
看上去方法好像挺多,其實(shí)真正能訪問(wèn)用的只有用@RemoteMethod標(biāo)注過(guò)的。
測(cè)試已經(jīng)好用了下面就是加到頁(yè)面了。那不就更簡(jiǎn)單了嗎。按著上圖收到JSP文件中。然后像調(diào)用普通javascript對(duì)象一樣就可以了。咱不是做普及的,今天主要講注釋的用法。這部分就到這吧。
下面說(shuō)反向調(diào)用了,這個(gè)還是挺復(fù)雜的,首先解釋幾個(gè)概念。
dwr的逆向ajax其實(shí)主要包括兩種模式:主動(dòng)模式和被動(dòng)模式。其中主動(dòng)模式包括Polling和Comet兩種,被動(dòng)模式只有Piggyback這一種。
所謂的Piggyback指的是如果后臺(tái)有什么內(nèi)容需要推送到前臺(tái)(即調(diào)用頁(yè)面的js方法),是要等到那個(gè)頁(yè)面進(jìn)行下一次ajax請(qǐng)求的時(shí)候,將需要推送的內(nèi)容附加在該次請(qǐng)求之后,傳回到頁(yè)面。
polling指的是由瀏覽器定時(shí)向服務(wù)端發(fā)送ajax請(qǐng)求,詢問(wèn)后臺(tái)是否有什么內(nèi)容需要推送,有的話就會(huì)由服務(wù)端返回推送內(nèi)容。這種方式和我們直接在頁(yè)面通過(guò)定時(shí)器發(fā)送ajax請(qǐng)求,然后查詢后臺(tái)是否有變化內(nèi)容的實(shí)現(xiàn)是類似的。只不過(guò)用了dwr之后這部分工作由框架幫我們完成了。
comet模式指的的當(dāng)服務(wù)端建立和瀏覽器的連接,將頁(yè)面內(nèi)容發(fā)送到瀏覽器之后,對(duì)應(yīng)的連接并不關(guān)閉,只是暫時(shí)掛起。如果后面有什么新的內(nèi)容需要推送到客戶端的時(shí)候直接通過(guò)前面掛起的連接再次傳送數(shù)據(jù)。
通過(guò)上面的解釋我們可以看到,這三種模式都有各自的優(yōu)缺點(diǎn)。從客戶端請(qǐng)求次數(shù)的角度來(lái)說(shuō),當(dāng)然是piggyback的模式最好。這個(gè)里面完全沒(méi)有額外的網(wǎng)絡(luò)請(qǐng)求,只有等到下次請(qǐng)求頁(yè)面主動(dòng)發(fā)起了,中間的變化內(nèi)容才傳遞回頁(yè)面。但是這也導(dǎo)致了這推送內(nèi)容的延時(shí),因?yàn)槟阃耆珱](méi)辦法知道頁(yè)面的下一次請(qǐng)求將在什么時(shí)候發(fā)起,也許頁(yè)面永遠(yuǎn)都沒(méi)有下一次請(qǐng)求。polling模式的網(wǎng)絡(luò)請(qǐng)求最為頻繁了,因?yàn)檫@時(shí)候頁(yè)面不管后臺(tái)有沒(méi)有更新的內(nèi)容,都需要發(fā)送請(qǐng)求詢問(wèn)。雖然這種模式可以通過(guò)增加請(qǐng)求間隔的時(shí)間來(lái)減少單位時(shí)間內(nèi)的請(qǐng)求次數(shù),但是這樣同樣會(huì)導(dǎo)致頁(yè)面響應(yīng)后臺(tái)內(nèi)容變化的間隔時(shí)間增長(zhǎng),這中間就產(chǎn)生了矛盾,具體的請(qǐng)求間隔時(shí)間還是要根據(jù)具體項(xiàng)目的需求來(lái)配置。比如服務(wù)器能承受的請(qǐng)求間隔和頁(yè)面內(nèi)容所需要的刷新頻率。comet方式的響應(yīng)速度應(yīng)該是最快的,后臺(tái)一旦有內(nèi)容需要推送可以通過(guò)前面沒(méi)有關(guān)閉的連接馬上推送到前臺(tái)。但是服務(wù)器所能提供的連接數(shù)目是一定的,在大量的掛起的連接沒(méi)有關(guān)閉的情況下,可能造成新的連接請(qǐng)求不能接入,從而影響到服務(wù)質(zhì)量。
以上摘自dwr的Reverse Ajax(推技術(shù)的實(shí)現(xiàn)之一)概念說(shuō)清楚了,下面做一吧。
前面已經(jīng)說(shuō)完了注釋方式了,以下還用注釋的方式,方便直觀呀。
@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(");");//調(diào)用頁(yè)面的javascript方法把值添到頁(yè)面上。
// Loop over all the users on the current page
Collection pages = wctx.getScriptSessionsByPage(currentPage);//循環(huán)出所有的會(huì)話頁(yè)面并執(zhí)行
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;
}
這是個(gè)簡(jiǎn)單的程序進(jìn)行之后就是用個(gè)循環(huán)來(lái)更新頁(yè)面的數(shù)字。
下面也貼一下JSP的代碼吧。也算補(bǔ)充下第一部分了。
<%@ 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>
運(yùn)行起來(lái)后點(diǎn)start按鈕,看看頁(yè)面上是不是自己開(kāi)始變了。新打開(kāi)個(gè)IE,用另外的機(jī)器訪問(wèn)此面,疑?怎么都有數(shù)字在變換,這就是DWR Reverse Ajax的厲害所在了。再點(diǎn)一下stop,呀,所有打個(gè)IE里數(shù)字都不變了吧。
注意:代碼用的是主動(dòng)的方式,所以注意頁(yè)面onload中的<body onload="dwr.engine.setActiveReverseAjax(true)">沒(méi)有這句可就不好用了。當(dāng)然 web.xml中也不能少了
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
該說(shuō)的都說(shuō)了就到這吧。這篇文章不是給初學(xué)者看的。所以不是特別的完整。如果你是初學(xué)者,就先去看看基礎(chǔ)吧。可能有點(diǎn)不適合你。
posted on 2009-08-13 14:37 輕松 閱讀(2930) 評(píng)論(3) 編輯 收藏 所屬分類: 其他文章