DWR推送技术
DWR2.x的推技术也叫DWRReverseAjax(逆向Ajax)主要是在BS架构中,从服务器端向多个浏览器主动推数据的一种技术。
在DWR所开的线程中使用ReverseAjax时,通过WebContextFactory.get()获取WebContext对象,进而获取脚本Session。
在DWR之外使用ReverseAjax时,就要用到ServerContext,在Spring环境中要得到ServerContext,就需要用到Spring的ServletContextAware接口。
一、ReverseAjax的实现有3种方式:
DWR的逆向Ajax主要包括两种模式:主动模式和被动模式。其中主动模式包括polling和comet两种,被动模式只有piggyback这一种。
1、piggyback方式
这是默认的方式。
如果后台有什么内容需要推送到前台,是要等到那个页面进行下一次ajax请求的时候,将需要推送的内容附加在该次请求之后,传回到页面。
只有等到下次请求页面主动发起了,中间的变化内容才传递回页面。
2、comet方式
当服务端建立和浏览器的连接,将页面内容发送到浏览器之后,对应的连接并不关闭,只是暂时挂起。如果后面有什么新的内容需要推送到客户端的时候直接通过前面挂起的连接再次传送数据。
服务器所能提供的连接数目是一定的,在大量的挂起的连接没有关闭的情况下,可能造成新的连接请求不能接入,从而影响到服务质量。
3、polling方式
由浏览器定时向服务端发送ajax请求,询问后台是否有什么内容需要推送,有的话就会由服务端返回推送内容。这种方式和我们直接在页面通过定时器发送ajax请求,然后查询后台是否有变化内容的实现是类似的。只不过用了dwr之后这部分工作由框架帮我们完成了。
二、使用DWR的推技术的步骤
1、在web.xml文件中增加以下配置信息
Xml代码
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<!--DWR默认采用piggyback方式-->
<!--使用polling和comet的方式-->
<init-param>
<param-name>pollAndCometEnabled</param-name>
<param-value>true</param-value>
</init-param>
<!--comet方式-->
<!--
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
-->
<!--polling方式:在comet方式的基础之上,再配置以下参数-->
<!--
<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>
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<!--DWR默认采用piggyback方式-->
<!--使用polling和comet的方式-->
<init-param>
<param-name>pollAndCometEnabled</param-name>
<param-value>true</param-value>
</init-param>
<!--comet方式-->
<!--
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
-->
<!--polling方式:在comet方式的基础之上,再配置以下参数-->
<!--
<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>
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>Xml代码
<listener>
<listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextAttributeListener</listener-class>
</listener>
<listener>
<listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextAttributeListener</listener-class>
</listener>Xml代码
<listener>
<listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextListener</listener-class>
</listener>
<listener>
<listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextListener</listener-class>
</listener>
2、在dwr.xml中增加以下配置信息
Xml代码
<createcreator="new"javascript="DWRHelper">
<paramname="class"value="com.cjm.web.dwr.DWRHelper"/>
<includemethod="addMessage"/>
<includemethod="test"/>
</create>
<convertconverter="bean"match="com.cjm.web.dwr.Message">
<paramname="include"value="id,text"/>
</convert>
<createcreator="new"javascript="DWRHelper">
<paramname="class"value="com.cjm.web.dwr.DWRHelper"/>
<includemethod="addMessage"/>
<includemethod="test"/>
</create>
<convertconverter="bean"match="com.cjm.web.dwr.Message">
<paramname="include"value="id,text"/>
</convert>
3、pojo类Message的源码
Java代码
publicclassMessage{
privatelongid=System.currentTimeMillis();
privateStringtext;
publicMessage(){
}
publicMessage(StringnewText){
text=newText;
}
publiclonggetId(){
returnid;
}
publicvoidsetId(longid){
this.id=id;
}
publicStringgetText(){
returntext;
}
publicvoidsetText(Stringtext){
this.text=text;
}
}
publicclassMessage{
privatelongid=System.currentTimeMillis();
privateStringtext;
publicMessage(){
}
publicMessage(StringnewText){
text=newText;
}
publiclonggetId(){
returnid;
}
publicvoidsetId(longid){
this.id=id;
}
publicStringgetText(){
returntext;
}
publicvoidsetText(Stringtext){
this.text=text;
}
}
4、DWRHelper类源码
Java代码
publicclassDWRHelper{
privatestaticLinkedList<Message>messages=newLinkedList<Message>();
privatestaticReentrantLocklock=newReentrantLock();//JDK5锁
publicvoidaddMessage(Stringtext){
try{
lock.lock();
if(text!=null&&text.trim().length()>0){
messages.addFirst(newMessage(text));
if(messages.size()>10){
messages.removeLast();
}
}
}catch(Exceptionex){
ex.printStackTrace();
}finally{
lock.unlock();
}
//获得DWR上下文
WebContextwebContext=WebContextFactory.get();
//获取当前页面URL,比如/ext3/test_tag.jsp
StringcurrentPage=webContext.getCurrentPage();
//当前脚本sessin
ScriptSessionscriptSession=webContext.getScriptSession();
//设置页面控件的值
Utilutil=newUtil(scriptSession);
util.setValue("text","");//这里是清空页面输入框的值
//设置脚本sessin的属性值
scriptSession.setAttribute("uid","cjm");
//获取脚本session的属性值
for(Iteratorit=scriptSession.getAttributeNames();it.hasNext();){
StringattrName=(String)it.next();
System.out.println(attrName+"="+scriptSession.getAttribute(attrName));
}
//获取所有浏览当前页面的脚本session
Collection<ScriptSession>sessions=webContext.getScriptSessionsByPage(currentPage);
UtilutilAll=newUtil(sessions);
//执行客户端脚本
ScriptBufferscript=newScriptBuffer();
script.appendScript("clientFunction(")
.appendData(scriptSession.getAttribute("uid"))
.appendScript(");");
for(ScriptSessionsession:sessions){
session.addScript(script);
}
//更新这些脚本session的一些元素
utilAll.removeAllOptions("messages");
utilAll.addOptions("messages",messages,"id","text");
}
}
publicclassDWRHelper{
privatestaticLinkedList<Message>messages=newLinkedList<Message>();
privatestaticReentrantLocklock=newReentrantLock();//JDK5锁
publicvoidaddMessage(Stringtext){
try{
lock.lock();
if(text!=null&&text.trim().length()>0){
messages.addFirst(newMessage(text));
if(messages.size()>10){
messages.removeLast();
}
}
}catch(Exceptionex){
ex.printStackTrace();
}finally{
lock.unlock();
}
//获得DWR上下文
WebContextwebContext=WebContextFactory.get();
//获取当前页面URL,比如/ext3/test_tag.jsp
StringcurrentPage=webContext.getCurrentPage();
//当前脚本sessin
ScriptSessionscriptSession=webContext.getScriptSession();
//设置页面控件的值
Utilutil=newUtil(scriptSession);
util.setValue("text","");//这里是清空页面输入框的值
//设置脚本sessin的属性值
scriptSession.setAttribute("uid","cjm");
//获取脚本session的属性值
for(Iteratorit=scriptSession.getAttributeNames();it.hasNext();){
StringattrName=(String)it.next();
System.out.println(attrName+"="+scriptSession.getAttribute(attrName));
}
//获取所有浏览当前页面的脚本session
Collection<ScriptSession>sessions=webContext.getScriptSessionsByPage(currentPage);
UtilutilAll=newUtil(sessions);
//执行客户端脚本
ScriptBufferscript=newScriptBuffer();
script.appendScript("clientFunction(")
.appendData(scriptSession.getAttribute("uid"))
.appendScript(");");
for(ScriptSessionsession:sessions){
session.addScript(script);
}
//更新这些脚本session的一些元素
utilAll.removeAllOptions("messages");
utilAll.addOptions("messages",messages,"id","text");
}
}
5、JSP页面源码
Html代码
<%@pagelanguage="java"pageEncoding="UTF-8"%>
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">
<html>
<head>
<scripttype='text/javascript'src='/ext3/dwr/engine.js'></script>
<scripttype='text/javascript'src='/ext3/dwr/util.js'></script>
<scripttype='text/javascript'src='/ext3/dwr/interface/DWRHelper.js'></script>
</head>
<!--通过dwr.engine.setActiveReverseAjax(true);启动该页面的ReverseAjax功能-->
<bodyonload="dwr.engine.setActiveReverseAjax(true);sendMessage();">
<p>输入信息:<inputid="text"onkeypress="dwr.util.onReturn(event,sendMessage)"/>
<inputtype="button"value="Send"onclick="sendMessage()"/></p>
<scripttype="text/javascript">
functionsendMessage(){
DWRHelper.addMessage(dwr.util.getValue("text"));
}
</script>
<hr/>
<selectid="messages"></select>
</body>
</html>