资源描述
dwr推技术.docx
《dwr推技术.docx》由会员分享,可在线阅读,更多相关《dwr推技术.docx(9页珍藏版)》请在冰豆网上搜索。
![dwr推技术.docx](https://file1.bdocx.com/fileroot1/2022-11/28/50e9c696-589f-406f-859b-a69dd1359b57/50e9c696-589f-406f-859b-a69dd1359b571.gif)
dwr推技术
DWR推技术在开发中需要注意的ScriptSession问题
(作者zhyiwww,转载请您注明出处,zhyi)
1关于ScriptSession
ScriptSession不会与HttpSession同时创建
当我们访问一个页面的时候,如果是第一次访问,就会创建一个新的HttpSession,之后再访问的时候,就会保持当前的Session,即使是刷新,也能保持当前的HttpSession。
但是,ScriptSession不同,第一次访问,会创建一个ScriptSession,但是,如果你刷新,就会创建一个新的ScriptSession.
2如何得到ScriptSession
在DWR中,我们可以通过WebContextFactory.get()来取得一个WebContext对象,进而通过WebContext的getScriptSession()取得ScriptSession对象。
但是要注意,在我们自定义的Servlet中,我们也可以通过WebContextFactory.get()来取得一个WebContext,但是这种方法却不能取得ScriptSession对象。
因为,此WebContext对象其实不是通过DWR的上下文环境得到的,所以,就根本没有创建ScriptSession对象。
假设这种方式也能得到ScriptSession的话,那么我们实现“推”也就可以不局限在DWR的上下文环境中了,那么其灵活性就会大很多了。
所以,这就是我们不能在Servlet中实现推的原因。
3关于刷新就创建一个新的ScriptSession问题
在我们需要推送的页面中,如果你刷新以下,那么就提交一个Http的request,此时,如果是第一次,那么就会创建一个httpSession对象,同时,请求由DwrServlet来处理后,就会创建一个ScriptSession.这个ScriptSession会和你的request请求的URI绑定放在一个由ScriptSessionManager维护的Map里面(这里面其实是一个URI对应的Set,在Set里面放置的是URI绑定的所有ScriptSession)。
当你刷新的时候,同样的一个HttpSession,却会创建一个新的ScriptSession,然后绑定到对应的URI上。
4向所有的页面访问者推送
当我们想向所有的页面访问者推送的时候,我们只需要,取得所有的页面访问者,就可以“推”了。
如何取得所有的页面访问者?
可以通过
// Collectionpages=webContext.getScriptSessionsByPage("/SynMap/map/map.jsp");
来取得/SynMap/map/map.jsp的所有访问的ScriptSession
如何推送,
Utilutil=newUtil(pages);
util.addFunctionCall("syningMap",newDouble(x),newDouble(y),newInteger(zoom));
通过此方法,就可以实现调用客户端的javascript函数,实现对客户端的操作。
5在上面的推送中产生的问题
上面的方法已经可以实现向所有的访问者推送。
但是问题是,在客户端,如果用户刷新一次或多次,那么,Collection里面可能就保存了很多的无用的ScriptSession,所以不仅仅会影响性能问题,更重要的是,可能就不能实现你想要的功能。
比如,你想取得当前再现的有效用户,那么你就需要知道那些ScriptSession是有效的。
6如何管理有效的ScriptSession
由于上面的问题,我们就需要自己管理ScriptSession.其实,有效地HttpSession,就是那个和当前的HttpSession匹配的ScriptSession.
所以,我们就可以自己维护一个Map,在这个Map里面,我们定义key就是HttpSession的Id,其值就是ScriptSession对象。
在每一次页面载入的时候,都去注册此ScriptSession,那么就会把新的ScriptSession绑定到httpSession上面了。
//sessionandscriptSessionmap
Mapsm=g.getSessions();
//hsisHttpSession
//ssisScriptSessionobject
sm.put(hs.getId(),ss);
7如何实现有效推送
通过上面的Map取得所有的有效ScriptSession集合
Collectionpages=g.getSessions().values();
然后再推送,就可以了。
8上面问题的新的解决方案
上面的技术问题和解决方案都是在DWR2.0的环境下遇到的。
昨天看了一下,即将正式发布的DWR3.0的文档,里面对AJAXReverse技术增加了不少功能。
其中新加了一个象HttpSessionListener的东西,叫ScriptSessionListener
所以,我想,可以通过这个Listener实现上面的功能,也就是说,在监听到一个ScriptSession创建的时候,我们就直接判断,并把此ScriptSession绑定到httpSession上,就可以了。
同样用上面的那个map来管理就可以了。
这个是我的思路,我还没有实践,如果你需要的话,可以自己去试一下。
新版本的DWR开发实现推技术会更加方便,期待吧!
!
1、服务器推技术
通过客户端发出请求获取服务器端数据的方式通常称为“拉”技术,很形象说明客户端在拉取服务器端数据,而有时候需要服务器端主动向客户端“推”数据,比如监测聊天上线人数主动向上线发送消息,后台数据库发生变化是主动更新所有客户端展示。
2、ReverseAjax实现服务器推技术
DWR2.x的推技术也叫DWRReverseAjax(逆向Ajax)主要是在BS架构中,从服务器端向多个浏览器主动推数据的一种技术。
DWR的逆向Ajax主要包括两种模式:
主动模式和被动模式。
其中主动模式包括polling和comet两种,被动模式只有piggyback这一种。
(1)piggyback方式,是默认的方式。
如果后台有什么内容需要推送到前台,是要等到那个页面进行下一次ajax请求的时候,将需要推送的内容附加在该次请求之后,传回到页面。
只有等到下次请求页面主动发起了,中间的变化内容才传递回页面。
(2)comet方式
当服务端建立和浏览器的连接,将页面内容发送到浏览器之后,对应的连接并不关闭,只是暂时挂起。
如果后面有什么新的内容需要推送到客户端的时候直接通过前面挂起的连接再次传送数据。
服务器所能提供的连接数目是一定的,在大量的挂起的连接没有关闭的情况下,可能造成新的连接请求不能接入,从而影响到服务质量。
(3)polling方式
由浏览器定时向服务端发送ajax请求,询问后台是否有什么内容需要推送,有的话就会由服务端返回推送内容。
这种方式和我们直接在页面通过定时器发送ajax请求,然后查询后台是否有变化内容的实现是类似的。
只不过用了dwr之后这部分工作由框架帮我们完成了。
3、配置web.xml使用reverseajax
(1)piggyback方式,默认的dwr在web.xml文件的配置即piggyback方式。
(2)comet需要增加如下配置
pollAndCometEnabled
true
activeReverseAjaxEnabled
true
(3)polling方式:
在comet方式的基础之上,再配置以下参数
org.directwebremoting.extend.ServerLoadMonitororg.directwebremoting.impl.PollingServerLoadMonitor
--毫秒数。
页面默认的请求间隔时间是5秒-->
disconnectedTime
60000
4、编写聊天消息处理类
publicclassMessageManager{
privatestaticListmsgList=newLinkedList();
publicListgetMsgList(){
returnmsgList;
}
publicsynchronizedvoidsendMessage(Stringmsg){
msgList.add(msg);
showMessage();
}
privatevoidshowMessage(){
WebContextwctx=WebContextFactory.get();
StringcurrentPage=wctx.getCurrentPage();
ScriptBufferscript=newScriptBuffer();script.appendScript("receiveMessages(").appendData(msgList).appendScript(");");//调用页面的javascript方法把值添到页面上。
Collectionpages=wctx.getScriptSessionsByPage(currentPage);//循环出所有的会话页面并执行
for(Iteratorit=pages.iterator();it.hasNext();){
ScriptSessionotherSession=(ScriptSession)it.next();
otherSession.addScript(script);
}
}
}
5、dwr.xml中配置聊天消息处理类
6、页面代码
DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">
ReverseAjax.html
dwr.engine.setActiveReverseAjax(true);
functionreceiveMessages(msg){
varmessage="";
for(vari=0;imessage+=msg[i]+"
";
$("content").innerHTML=message
}
functioninit(){
messageManager.getMsgList(callback);
functioncallback(msg){
varmessage="";
for(vari=0;imessage+=msg[i]+"
";
$("content").innerHTML=message
}
}
window.onload=init;
send
1、首先要下载dwr3.0地址http:
//directwebremoting.org/dwr/download.html
2、在web.xml中加入dwr的servlet和相关配置
--dwrservlet-->
dwr-invoker
uk.ltd.getahead.dwr.DWRServlet
debug
true
pollAndCometEnabled
true
1
dwr-invoker
/dwr/*
pollAndCometEnabled是指dwr的reverseajax是使用polling和comet的方式,在这个例子中可以明显地从页面上看出来是用的polling+comet
附:
关于reverse-ajax的实现有3种方式
polling 就是隔一段时间向服务器发送一request来检查服务端是否有数据更新
comet 就是一个长http请求,在请求期间服务端可以向客户端push数据,但是这种做法要求server和brower长期建立一个通信通道,而且效率很低
piggyback就是服务端的更新数据都在排队等待,等到下一次有请求过来,那么这些等待更新数据就伴随这次请求一起发送到brower
有关更详细的reverse-ajax技术介绍可以参考http:
//getahead.org/dwr/reverse-ajax
3、创建一个dwr.xml,用于配置你要制定的java代码映射类,以及允许使用的方法和converter
xmlversion="1.0"encoding="UTF-8"?
>
DOCTYPEdwrPUBLIC
"-//GetAheadLimited//DTDDirectWebRemoting1.0//EN"
"http:
//www.getahead.ltd.uk/dwr/dwr10.dtd">
create是只一个java的js映射,其中include是可以在js使用的方法
convert是指对应js到java,或者java到js的对象转换,其中include是可以转换的属性
4、写服务段的java代码
DWRHelper
packagecom.cloverworxs.uma.helper;
importjava.util.Collection;
importjava.util.LinkedList;
importorg.directwebremoting.WebContext;
importorg.directwebremoting.WebContextFactory;
importorg.directwebremoting.proxy.dwr.Util;
publicclassDWRHelper{
publicvoidaddMessage(Stringtext,Stringname){
StringtempStr=name+"说:
"+text;
LinkedListmessages=newLinkedList();
if(text!
=null&&text.trim().length()>0){
messages.addFirst(newMessage(tempStr));
//messages.addLast(newMessage(text));
while(messages.size()>10){
messages.removeLast();
}
}
//ReverseAjaxcodetobeaddedhereshortly
WebContextwctx=WebContextFactory.get();
StringcurrentPage=wctx.getCurrentPage();
//Cleartheinputboxinthebrowserthatkickedoffthispageonly
UtilutilThis=newUtil(wctx.getScriptSession());
utilThis.setValue("text","");
//Forallthebrowsersonthecurrentpage:
Collectionsessions=wctx.getScriptSessionsByPage(currentPage);
UtilutilAll=newUtil(sessions);
//Clearthelistandaddinthenewsetofmessages
utilAll.removeAllOptions("chatlog");
utilAll.addOptions("chatlog",messages,"text");
}
}
Message
packagecom.cloverworxs.uma.helper;
importorg.directwebremoting.Security;
publicclassMessage{
publicMessage(Stringnewtext){
text=newtext;
if(text.length()>256){
text=text.substring(0,256);
}
text=Security.replaceXmlCharacters(text);
}
publiclonggetId(){
returnid;
}
publicStringgetText(){
returntext;
}
privatelongid=System.currentTimeMillis();
privateStringtext;
}
5、到此为止可以写页面代码了,下面的代码html或者jsp都可以
<%@pagelanguage="java"contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8"%>
DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http:
//www.w3.org/TR/html4/loose.dtd">
Inserttitlehere
JavaChat