利用dwr框架来实现“服务推”技术的方法:
n 官网上主要有三种方法:
1.Polling:轮询是解决此问题最常见的方法。浏览器不断对服务端发起一个请求,来检测页面(数据)是否有更新。举个例子:就像是一个几岁的小孩跟在汽车后面不断的喊“我们在这里”。
2.Comet:通过这种方法服务器可以缓慢的响应客户端的请求,持续响应有服务器管理的任务表。更多信息参考:
· Alex Russell's original post coining the term
· The Wikipedia article on Comet
· Comet Daily, a blog with regular posts on the subject
3.Piggyback:采用这种方法,如果有数据更新,服务端等待客户端的连接后发送数据。
三种方法比较:
Polling方法容易实现,但也容易增加服务器负担。和Comet相比,comet不会使用太多的服务器资源,同时,低延迟,因为不需要等待浏览器的下次连接。Polling和comet都要求额外的网络连接,即长连接,所以piggyback是低负载的最佳方法,但延迟高。
n 如何使用dwr框架
(1)准备相关jar,包括dwr.jar,commons-logging.jar,并将它们放到/WEB-INF/lib目录下;如果使用maven,则不需求添加jar,直接在pom.xml文件中的<dependencies>标签中添加如下内容:
<!--使用dwrjar包,必须添加的两个jar包,dwr.jar和commons-logging.jar-->
<dependency>
<groupId>org.directwebremoting</groupId>
<artifactId>dwr</artifactId>
<version>2.0.10</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
(2)映射文件
a)映射文件的配置,将如下代码添加到应用的web.xml文件中
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
b)映射文件的添加,文件名为dwr.xml的文件放到与web.xml文件同一级目录,其dwr.xml文件内容如下所示:注意:这个文件是和你的Java Bean一起写的。
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd"> <dwr> <allow> <create creator="new" javascript="JDate"> <param name="class" value="java.util.Date"/> </create> <create creator="new" javascript="Demo"> <param name="class" value="your.java.Bean"/> </create> </allow></dwr>
(3)测试DWR驱动,刚才添加的类是否起作用,访问http://localhost:8080/[项目名称]/dwr/得到刚才添加的类(项目名称不一定非得添加,根据你自己项目的部署情况)
结果如下图所示:
点击超链接进去某个类并进行方法的测试:
图2
如果有参数输入参数并直接点击Execute即可,原理是通过js来调用Java代码。
(4)以上步骤基本完成,但是boss或客户肯定看不懂,那么怎么转换成客户看的懂的东西?
a)新建一个HTMl或JSP文件,如index.jsp
将图2中的js文件即以下内容添加到index.jsp中,如下所示,注意文件路径问题,自己把握。
<script type='text/javascript' src='/dwr/interface/Hello.js'></script><script type='text/javascript' src='/dwr/engine.js'></script>
<script type='text/javascript' src='/dwr/util.js'></script>
b)写js代码通过js来调用Java代码:
如下所示:
<script type="text/javascript">
function hello(){
var user=$('user').value;
Hello.sayHello(user,callback);
}
function callback(msg){
dwr.util.setValue('result',msg);
}
</script>
<body>
<input id="user" type="text">
<input type="button" value="打招呼" οnclick="hello()">
<div id="result"></div>
</body>
其中user是sayHello()方法的参数,callback是回调函数,如果java中的方法没有返回参数就不需要。
其实系统自动生成的Execute方法就相当于此处的hello()方法
n 如何使用DWR实现Reverse Ajax(Server Push),以服务端的文本数据的变化从而推送到客户端为例来介绍。
0.1)通用配置,无论使用哪种方法都要在web.xml文件中添加如下配置:该配置意思是激活反Ajax
<servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class> <init-param> <param-name>activeReverseAjaxEnabled</param-name> <param-value>true</param-value> </init-param></servlet>
0.2)在web网页中激活反Ajax请求,在页面中添加如下代码即可:
dwr.engine.setActiveReverseAjax(true);
(1)新建一个SendData类并在dwr.xml文件中配置
a)SendData类中代码的主要思想:实现思路:在类的构造函数中构造一个任务定时器,利用任务定时器按时执行主任务(例如.显示数据到页面)
主要代码如下所示:
public SendData() {
//定义一个执行任务的线程池,池中线程为1
executor=new ScheduledThreadPoolExecutor(1);
//60s执行一次
executor.scheduleAtFixedRate(this,1,60, TimeUnit.SECONDS);
}
@Override
public void run() {
//执行主任务:及时向客户端发送更新后的数据
sendDataTimely();
}
public void sendDataTimely() {
//准备数据
String filePath = "D:/text.txt";
BufferedReader reader = null;
final StringBuffer sb = new StringBuffer();
try {
reader = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath), "UTF-8"));
String tempString = null;
while ((tempString = reader.readLine()) != null) {
sb.append(tempString + "\n\r");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//显示数据 将数据发送到根目录下的showdata.html文件中
String page = ServerContextFactory.get().getContextPath()
+ "/showdata.html";
Browser.withPage(page, new Runnable() {
public void run() {
//将内容显示到showdata页面中的“id=content”元素中
Util.setValue("content", sb.toString());
}
});
}
(2)新建一个showdata.html页面,主要代码如下:
<script>
window.onload = function () {
dwr.engine.setActiveReverseAjax(true);
dwr.engine.setErrorHandler(errorHandler);
dwr.engine.setNotifyServerOnPageUnload(true);
SendData.addAttributeToScriptSession();
}
function errorHandler(message, ex) {
dwr.util
.setValue(
"error",
"<font color='red'>Cannot connect to server. Initializing retry logic.</font>",
{
escapeHtml: false
});
setTimeout(function () {
dwr.util.setValue("error", "");
}, 5000)
}
</script>
实现的效果是:如果D:/text.txt下的文本发生变化,会在1min中后同步更新到客户端中。
源代码地址如下:
Git:https://github.com/weichenjushi/dwr.helloworld.git
Svn:https://github.com/weichenjushi/dwr.helloworld
n 注意事项:
1)如果使用DWR3的话,可能会弹框
解决办法:将以下代码添加到配置的DWRServlet的配置文件中:
<init-param>
<param-name>crossDomainSessionSecurity</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>allowScriptTagRemoting</param-name>
<param-value>true</param-value>
</init-param>