基于dwr2.0的Push推送技术详细解析以及实例(转)
DWR从2.0开始增加了push功能,也就是在异步传输的情况下可以从Web-Server端发送数据到
Browser.
我们知道,Web的访问机制天生是设计用来pull数据的,也就是只允许Browser端主动发起请求,server
是被动的响应.不允许Server向Browser发出一个connection请求,也就是说没有为server向Browser
push数据提供设计实现.
虽然没有直接的实现方法,却可以使用一些变通的方式完成类似的功能:
1. Polling
Polling其实就是轮询,是通过Browser在一个相对短的间隔时间内,反复向Server发出请求,然
后更新页面,这种方式没有什么新鲜的,只是需要浏览器端做一些工作就可以,哪怕没有太多服务器端的配
置也没问题.轮询的方式对于服务器来说会依据不同的访问间隔而产生不同程度的额外负载,因为每次访
问都有重新建立连接的过程.
2. Comet
Comet方式通俗的说就是一种长连接机制(long lived http).同样是由Browser端主动发起请
求,但是Server端以一种似乎非常慢的响应方式给出回答,这样在这个期间内,服务器端可以使用同一个
connection把要更新的数据主动发送给Browser.Comet又有很多中实现方式,但是总的来说对Server
端的负载都会有增加.虽然对于单位操作来说,每次只需要建议一次connection,但是由于connection是
保持较长时间的,对于server端的资源的占用要有所增加.
3. Piggyback
Piggyback方式是一种半主动的方式,也就是说还是由Browser主动发出请求,但是每次请求的
响应中除了当次的响应之外,还会把上次请求以来已经发生的变化同时发给Browser.也就是说,当次请
求的更新会搭载到下一次请求的响应中一并发回.这样,在Browser的感觉就好象上一次请求又有了更
新.但是这种感觉取决于Browser向Server发出请求的频度.如果,第二次请求迟迟没有发出,那么上一次
的更新就不会取到.
在DWR2.0中可以使用Active(主动) 和 Passive(被动)两种工作模式,在这里我们主要讨论
Active(主动)模式.Active(主动)模式又分为以下3种:
• Full Streaming Mode
• Early Closing Mode
• Polling Mode
Full Streaming Mode
这是Active模式下的一种默认配置,具有很快的响应速度,而且建立好的链接只有每60秒检查一次浏
览器是否是活跃的.这种工作模式的配置非常简单,在Web.xml中配置DWR的时候,加上下面的内容:
1
|
< servlet >
|
2
|
< servlet-name >dwr-invoker</ servlet-name >
|
3
|
< servlet-class >org.directwebremoting.servlet.DwrServlet</ servlet-class >
|
4
|
< init-param >
|
5
|
< param-name >activeReverseAjaxEnabled</ param-name >
|
6
|
< param-value >true</ param-value >
|
7
|
</ init-param >
|
8
|
</ servlet >
|
然后在Browser页面端加上下面一句就可以了:
dwr.engine.setActiveReverseAjax(true);
需要说明的是,长链接会增加Server的资源占用,有些Server比如Jetty允许在客户端关闭线程
(connection),在新版本中会把这种能力延伸到GlassFish 和Tomcat.总之,DWR的主导思想是尽
量保护Server,减小负载.
Early Closing Mode
在Browser和Server之间有Proxy或者mod_jk的情况下,需要能够良好的工作,需要这种模式:这种
模式和Full Streaming Mode相似,以Full模式开启connection,但是,如果没有输出的情况下,
它会在一个配置好的时间内关闭Connection,通常这个时间是60秒.
从2.04版开始,DWR默认使用Early Closing Mode,如果要要想使用Full Streaming Mode,需
要进行如下的配置:
1
|
< init-param >
|
2
|
< param-name >maxWaitAfterWrite</ param-name >
|
3
|
< param-value >-1</ param-value >
|
4
|
</ init-param >
|
这里,设置maxWaitAfterWrite是-1,表示这个时间和Full Streaming Mode一样,设置关闭时间是60
秒.
Polling Mode
Polling Mode 是一种轮询方式,这可以避免长时间保持连接而产生的对服务器资源的占用.如果要是用
轮询方式,还需要做以下的配置:
1
|
< init-param >
|
2
|
< param-name >org.directwebremoting.extend.ServerLoadMonitor</ param-name >
|
3
|
< param-value >org.directwebremoting.impl.PollingServerLoadMonitor</ param-value >
|
4
|
</ init-param >
|
1
|
< init-param >
|
2
|
< param-name >disconnectedTime</ param-name >
|
3
|
< param-value >60000</ param-value >
|
4
|
</ init-param >
|
这是将轮询周期改为6000毫秒,也就是6秒
让Web具备了Push的方式,这对于很多应用是梦寐以求的,比如,如果有一个基于Web的网络聊天系统,
如果使用Push技术可以更加满足功能的需要,还有比如说一些需要server端根据数据条件主动向
browser端发送数据的应用需求,都非常需要这样的功能.
下面就举一个股票报盘的例子,能够让Server端通过主动的方式想Browser端发送股票信息.
先说一下所需jar包:dwr.jar commons-logging.jar
然后介绍如何配置:
1. 在web.xml中配置如下内容:
01
|
< servlet >
|
02
|
< servlet-name >dwr-invoker</ servlet-name >
|
03
|
< servlet-class >org.directwebremoting.servlet.DwrServlet</ servlet-class >
|
04
|
< init-param >
|
05
|
< param-name >activeReverseAjaxEnabled</ param-name >
|
06
|
< param-value >true</ param-value >
|
07
|
</ init-param >
|
08
|
</ servlet >
|
09
|
< servlet-mapping >
|
10
|
< servlet-name >dwr-invoker</ servlet-name >
|
11
|
< url-pattern >/dwr/*</ url-pattern >
|
12
|
</ servlet-mapping >
|
2. 在dwr.xml中配置如下内容:
1
|
< dwr >
|
2
|
< allow >
|
3
|
<!-- Reverse Ajax Stock push Demo Config -->
|
4
|
< create creator = "new" javascript = "StocksPusher" >
|
5
|
< param name = "class" value = "dwr.reverse.StocksPusher" />
|
6
|
</ create >
|
7
|
</ allow >
|
8
|
</ dwr >
|
3. 股票报盘的页面getStockInfo.html
01
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
02
|
"http://www.w3.org/TR/html4/loose.dtd">
|
03
|
< html >
|
04
|
< head >
|
05
|
< meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" />
|
06
|
< title >DWR Reverse Ajax Demo : Show Stock info</ title >
|
07
|
< link rel = "stylesheet" type = "text/css" href = "generic.css" />
|
08
|
< script type = 'text/javascript' src = '/AjaxShow/dwr/engine.js' ></ script >
|
09
|
< script type = 'text/javascript' src = '/AjaxShow/dwr/util.js' ></ script >
|
10
|
< script type = 'text/javascript' src='/AjaxShow/dwr/interface/
|
11
|
StocksPusher.js'></ script >
|
12
|
< script type = "text/javascript" >
|
13
|
function beginShow() {
|
14
|
StocksPusher.beginShow();
|
15
|
StocksPusher.sendStocks();
|
16
|
}
|
17
|
function endShow(){
|
18
|
StocksPusher.closeShow();
|
19
|
}
|
20
|
</ script >
|
21
|
</ head >
|
22
|
< body onload = "dwr.engine.setActiveReverseAjax(true);" >
|
23
|
< h3 >使用DWR Reverse Ajax进行股票报盘</ h3 >
|
24
|
< p >下面显示的股票信息是可以动态变化的</ p >
|
25
|
< input type = "button" value = "开市..." onclick = "beginShow()" />
|
26
|
=========================
|
27
|
< input type = "button" value = "闭市..." onclick = "endShow()" />
|
28
|
< hr >
|
29
|
< table style = "width:500px" border = "0" cellpadding = "0" >
|
30
|
< tr >
|
31
|
< td class = "headName" >< b >Stock Name</ b ></ td >
|
32
|
< td class = "headValue" >< b >Stock Value</ b ></ td >
|
33
|
</ tr >
|
34
|
< tr >< td >中移动</ td >< td >< div id = "zyd" >wait...</ div ></ td ></ tr >
|
35
|
< tr >< td >中石化</ td >< td >< div id = "zsh" >wait...</ div ></ td ></ tr >
|
36
|
< tr >< td >中石油</ td >< td >< div id = "zsy" >wait...</ div ></ td ></ tr >
|
37
|
< tr >< td >海尔电器</ td >< td >< div id = "hedq" >wait...</ div ></ td ></ tr >
|
38
|
< tr >< td >冀东水泥</ td >< td >< div id = "jdsn" >wait...</ div ></ td ></ tr >
|
39
|
< tr >< td >用友软件</ td >< td >< div id = "yyrj" >wait...</ div ></ td ></ tr >
|
40
|
< tr >< td >柳钢股份</ td >< td >< div id = "lggf" >wait...</ div ></ td ></ tr >
|
41
|
< tr >< td >招商银行</ td >< td >< div id = "zsyh" >wait...</ div ></ td ></ tr >
|
42
|
< tr >< td >中国铁建</ td >< td >< div id = "zgtj" >wait...</ div ></ td ></ tr >
|
43
|
< tr >< td >深发展</ td >< td >< div id = "sfz" >wait...</ div ></ td ></ tr >
|
44
|
< tr >< td >金山软件</ td >< td >< div id = "jsrj" >wait...</ div ></ td ></ tr >
|
45
|
< tr >< td >大连实德</ td >< td >< div id = "dlsd" >wait...</ div ></ td ></ tr >
|
46
|
< tr >< td >九寨沟</ td >< td >< div id = "jzg" >wait...</ div ></ td ></ tr >
|
47
|
< tr >< td >中国平安</ td >< td >< div id = "zgpa" >wait...</ div ></ td ></ tr >
|
48
|
< tr >< td >工商银行</ td >< td >< div id = "gsyh" >wait...</ div ></ td ></ tr >
|
49
|
< tr >< td >鞍钢股份</ td >< td >< div id = "aggf" >wait...</ div ></ td ></ tr >
|
50
|
< tr >< td >中国航天</ td >< td >< div id = "zght" >wait...</ div ></ td ></ tr >
|
51
|
</ table >
|
52
|
< br >
|
53
|
</ body >
|
54
|
</ html >
|
4. 报盘的主程序StocksPusher.java ,关键部分在代码后面有中文注释
01
|
package dwr.reverse;
|
02
|
import java.util.ArrayList;
|
03
|
import java.util.Collection;
|
04
|
import java.util.List;
|
05
|
import org.directwebremoting.WebContext;
|
06
|
import org.directwebremoting.WebContextFactory;
|
07
|
import org.directwebremoting.proxy.dwr.Util;
|
08
|
import org.directwebremoting.util.Logger;
|
09
|
/**
|
10
|
* Reverse Ajax class.
|
11
|
*
|
12
|
* @author Henry Huang
|
13
|
*/
|
14
|
public class StocksPusher {
|
15
|
private static boolean closeMarket = false ;
|
16
|
/**
|
17
|
* Initialize the stocklist with values.
|
18
|
*/
|
19
|
public StocksPusher() {
|
20
|
}
|
21
|
/**
|
22
|
* Send the Stock-Values to the file "getStockInfo.html"
|
23
|
*/
|
24
|
public void sendStocks() throws InterruptedException {
|
25
|
WebContext wctx = WebContextFactory.get(); //这里是获取WebContext上下文
|
26
|
String currentPage = wctx.getCurrentPage(); //从上下文中获取当前页面,这些是DWR
|
27
|
Reverse Ajax 要求的必须方式
|
28
|
Collection sessions = wctx.getScriptSessionsByPage(currentPage); //再一个page中
|
29
|
可能存在多个ScriptSessions,
|
30
|
Util utilAll = new Util(sessions); //Util 是DWR 在Server端模拟Brower端 dwr.util.js
|
31
|
的类, Engine也是
|
32
|
while ( true ){
|
33
|
Thread.sleep( 500 );
|
34
|
if (closeMarket) break ;
|
35
|
StocksBean stock = StockPriceTracer.getNextStockInfo();
|
36
|
utilAll.setValue(stock.getStock(), stock.getValue()); //这里的setValue()用法和
|
37
|
dwr.util.js中的setValue()函数用法完全一样,第一个参数是页面Element的id ,第二个参数是对该id
|
38
|
赋的新值
|
39
|
System.out.println( "Pushing stock: " + stock.getStock() + " = " +
|
40
|
stock.getValue());
|
41
|
}
|
42
|
}
|
43
|
public void beginShow(){
|
44
|
closeMarket = false ;
|
45
|
}
|
46
|
public void closeShow(){
|
47
|
closeMarket = true ;
|
48
|
}
|
49
|
}
|
5. 还有一个类是为了模拟实时获取股票信息的工具StockPriceTracer.java,也可能是访问数据库,
也可能来至卫星的大盘数据,等等,这个类是用随机的方法获得股票价格:
01
|
package dwr.reverse;
|
02
|
import java.util.ArrayList;
|
03
|
import java.util.List;
|
04
|
import java.util.Random;
|
05
|
import java.util.Stack;
|
06
|
/**
|
07
|
* Reverse Ajax class.
|
08
|
*
|
09
|
* @author Henry Huang
|
10
|
*/
|
11
|
public class StockPriceTracer {
|
12
|
private static StockPriceTracer tracer = null ;
|
13
|
private List<StocksBean> stocks = new ArrayList<StocksBean>();
|
14
|
private Stack<StocksBean> cycleStack = new Stack<StocksBean>();
|
15
|
private StockPriceTracer(){
|
16
|
stocks.add( new StocksBean( "zsy" , "36.55" ));
|
17
|
stocks.add( new StocksBean( "dlsd" , "91.01" ));
|
18
|
stocks.add( new StocksBean( "zsh" , "22.59" ));
|
19
|
stocks.add( new StocksBean( "lggf" , "5.07" ));
|
20
|
stocks.add( new StocksBean( "hedq" , "71.77" ));
|
21
|
stocks.add( new StocksBean( "jdsn" , "31.61" ));
|
22
|
stocks.add( new StocksBean( "yyrj" , "51.29" ));
|
23
|
stocks.add( new StocksBean( "zsyh" , "52.70" ));
|
24
|
stocks.add( new StocksBean( "zgtj" , "16.96" ));
|
25
|
stocks.add( new StocksBean( "sfz" , "54.34" ));
|
26
|
stocks.add( new StocksBean( "jsrj" , "178.48" ));
|
27
|
stocks.add( new StocksBean( "zyd" , "134.48" ));
|
28
|
stocks.add( new StocksBean( "jzg" , "76.32" ));
|
29
|
stocks.add( new StocksBean( "zgpa" , "80.63" ));
|
30
|
stocks.add( new StocksBean( "gsyh" , "18.79" ));
|
31
|
stocks.add( new StocksBean( "aggf" , "20.19" ));
|
32
|
stocks.add( new StocksBean( "zght" , "11.13" ));
|
33
|
}
|
34
|
public static StocksBean getNextStockInfo(){
|
35
|
if ( null == tracer) tracer = new StockPriceTracer();
|
36
|
if (tracer.cycleStack.empty()) tracer.cycleStack.addAll(tracer.stocks);
|
37
|
StocksBean tmp = tracer.cycleStack.pop();
|
38
|
tmp.setValue(tracer.getRandomPrice(tmp.getValue()));
|
39
|
return tmp;
|
40
|
}
|
41
|
private String getRandomPrice(String current){
|
42
|
float fcurrent = 0 .0F;
|
43
|
try {
|
44
|
fcurrent = Float.parseFloat(current);
|
45
|
} catch (NumberFormatException e){
|
46
|
fcurrent = 0 .01F;
|
47
|
}
|
48
|
Random rdm = new Random();
|
49
|
float tmp = fcurrent + rdm.nextFloat();
|
50
|
return String.valueOf(tmp);
|
51
|
}
|
52
|
}
|
6. 还有一个类是一个JavaBeanStockBean.java
01
|
package dwr.reverse;
|
02
|
public class StocksBean {
|
03
|
private String stock = "" ;
|
04
|
private String value = "" ;
|
05
|
public StocksBean(String stock, String value) {
|
06
|
this .setStock(stock);
|
07
|
this .setValue(value);
|
08
|
}
|
09
|
public String getStock() {
|
10
|
return stock;
|
11
|
}
|
12
|
public void setStock(String stock) {
|
13
|
this .stock = stock;
|
14
|
}
|
15
|
public String getValue() {
|
16
|
return value;
|
17
|
}
|
18
|
public void setValue(String value) {
|
19
|
this .value = value;
|
20
|
}
|
21
|
}
|
基于dwr2.0的Push推送技术详细解析以及实例(转)相关推荐
- 基于dwr2.0的Push推送技术详细解析以及实例
DWR从2.0开始增加了push功能,也就是在异步传输的情况下可以从Web-Server端发送数据到 Browser. 我们知道,Web的访问机制天生是设计用来pull数据的,也就是只允许Browse ...
- Android消息推送:第三方消息推送平台详细解析
前言 消息推送在Android开发中应用的场景是越来越多了,比如说电商产品进行活动宣传.资讯类产品进行新闻推送等等,如下图: 本文将介绍Android中实现消息推送的第三方推送的详细解决方案 阅读本文 ...
- 【AJAX】AJAX技术详细解析以及实例
Ajax技术介绍: 全称: Asynchronized(异步) JavaScript And Xml 技术组成有: Javascript.DOM.CSS 和 XMLHttpRequest AJAX ...
- 深入了解 cometd的服务器推送技术
简介:服务器推送技术已经出来一段时间了,业界上也有不少基于这种技术(应该说是设计模式)的开源实现,但是要移植或者说应用到自己的项目上都比较麻烦.Dojo 这样一个大型的 Web2.0 开发框架提供了一 ...
- PHP ServerPush (推送) 技术的探讨
转自:http://blog.163.com/bailin_li/blog/static/17449017920124811524364/ 需求: 我想做个会员站内通知的功能.不想用以前的ajax查询 ...
- Webserver推送技术
server推送(Server Push) 推送技术的基础思想是将浏览器主动查询信息改为server主动发送信息.server发送一批数据,浏览器显示这些数据,同一时候保证与server的连接.当se ...
- PHP:ServerPush (Comet推送) 技术的探讨
PHP中Push(推送)技术的探讨 [http://vistaswx.com/blog/article/php-server-push] 随着人们对Web即时应用需求的不断上升,Server Pus ...
- 58同城高性能移动Push推送平台架构演进之路
本文详细讲述58同城高性能移动Push推送平台架构演进的三个阶段,并介绍了什么是移动Push推送,为什么需要,原理和方案对比:移动Push推送第一阶段(单平台)架构如何设计:移动Push推送典型性能问 ...
- 1.认识服务器推送技术
最近需要使用服务器端往前台推送消息 ,所以查阅了相关资料 转载于:http://blog.csdn.net/zamaolangzi/article/details/7238688 仁兄的一篇文章, 服 ...
最新文章
- c++ memset 语言_自学C语言不知道从哪儿下手?学习框架都帮你列好了!
- 封闭已久的智能驾驶系统,在云栖大会上,被敲开一个裂缝
- 安卓蓝牙调试软件和微信小程序搜索不到设备
- 7-29 修理牧场 (25 分)
- oracle数据库dba密码,Oracle数据库的找回DBA账户的密码
- vapor mysql_vapor MySQL 作为Cache
- php中get结合mysql_php中,$_GET中的数值能被mySQL读到么?
- IIS7.5安全配置研究
- 班尼机器人怎么语音_每日一句中话西说巧学英语:“我们今天就到这儿吧。”英语怎么说?...
- python中kmeans怎么导入数据集_通过Python实践K-means算法
- linux:如何修改用户的密码
- Linux系统GCC常用命令和GCC编译过程描述
- c语言编程 猜字游戏
- 模组使用之常见认证,CCC认证,SRRC认证,ROHS认证,NAL认证
- (更新至v0.108)termux下载、安装教程 版本v0.88
- Python实现图片转pdf
- 【入门】萌新IP入门常识(一):什么是IP地址和代理IP
- Windows文件换行符转Linux换行符
- 2022/12/17 mysql 索引基本原理解读
- mysql 介绍 怎么下载 驱动jar包 各种细节问题大详解