网络上的DWR(Direct Web Remoting)的Helloworld五花八门,阅读了其中的几篇Helloworld,只觉得其作者写得太烦太杂,里面杂糅着许多技术,struts2有之,jquery有之,这些高大上的东西不是DWR必须的,DWR仅仅是需要本来就存在的javascript罢了。
关键是DWR的核心没有体现出来,DWR作用是一个页面在刷新的情况下不停地接收服务器发来的数据,部分DWR的Helloworld把发送数据与接收数据都写在一个页面了,让人无法清晰地了解里面接收数据与发送数据的过程。
其实DWR根本就无需这些东西,仅仅需要一个简单的dwr.jar就足够了,低版本的Tomcat还需要commons-logging-1.1.1.jar,这个包很常见到网上一搜索就有了。dwr.jar可以到官网下载(点击打开链接),笔者也上传了一份里面包含了以上包与web.xml的压缩包(点击打开链接),可以自行下载。
一、基本目标
在Tomcat服务器上编写两个页面,一个dwrsend.html与dwrec.html,dwrec.html接收dwrsend.html发过来的信息,在这期间dwrec.html无需手动刷新,如下图:
上图中,dwrrec窗口一直是处于非激活状态的,笔者根本不可能点过去按F5……
同时请注意,这是纯正的html页面,与jsp技术也没有半毛子的关系,但是dwr由于在其web.xml配置了servlet的东西,所以也必须扔到服务器中处理,但在开发过程中,开发者无需理会。
二、制作过程
1、基本配置
在Eclipse/Myeclipse中新建一个web工程,命名随意,切记下面的J2EE选择5.0或以上,笔者低版本的Myeclipse6.5默认是J2EE 1.4的,J2EE版本太低用不了DWR。
在创建出来的web工程webroot\web-inf\lib放入刚才下载好的commons-logging-1.1.1.jar与dwr.jar,
之后写好webroot\web-inf的web.xml,把下面的代码复制到你的web.xml,如果你的web.xml原本有其他东西则添加如下的<servlet>与<servlet-mapping>节点,当然请注意web-app version的内容,如果没有其他东西则直接覆盖吧,不要问我为什么,如果不这样写,DWR根本运行不了,甚至你的WEB工程都运行不了,web.xml是WEB工程最棘手的东西,弄不好很麻烦的。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<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>
<init-param>
<param-name>pollAndCometEnabled</param-name>
<param-value>true</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>
</web-app>
然后再于同一目录WEB-INF下面创建一个dwr.xml里面的内容很简单,但麻雀虽小五脏俱全。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
"http://getahead.ltd.uk/dwr/dwr20.dtd">
<dwr>
<allow>
<create creator="new" javascript="aaa" scope="application">
<param name="class" value="dwr.hello"/>
</create>
</allow>
</dwr>
注意allow节点下面的create标签,这样写,意味着你需要在src下目录创建一个package名为dwr的包,而且这个包下有一个hello.java文件,hello.java里面的所有方法,比如hello.java中有一个 public void a(){},以后在dwrsend.html与dwrec.html的脚本文件中的可以通过aaa.a()去调用这个方法。
这正是dwr的特性之一,可以在前台页面调用后台函数,dwr.xml正是把hello中的所有方法映射到前台的aaa中,以aaa代替hello,把hello表现出来。
既然如此,创建完两个html页面dwrsend.html与dwrec.html之后,就马上在src文件夹中创建package dwr并且在旗下创建hello.java,此时web工程的文件列表如下:
打开tomcat调试,发现没有任何错误的!那么基本配置到此结束,开始完善各个部分的内容。
2、hello.java
package dwr;
//需要使用到map的数据结构,然后是两个如果使用dwr就必须存在的包
import java.util.*;
import org.directwebremoting.*;
import org.directwebremoting.proxy.dwr.*;
public class hello {
// map实质是一个二维数组,每一个位置,存放一个页面名称,与页面session
// 此页面session不同于httpsession,httpsession关闭页面不超时,不杀死仍然存在,此页面session一刷新页面就没有了
// 页面session实质是用来标识每一个页面的
private static Map<String, ScriptSession> scrSessionMap = new HashMap<String, ScriptSession>();
// 把页面注册到map之后,比如dwrsend.html页面,随机给你一串随机数aaa,然后,以后要控制这一页,我们需要操纵这串随机数
// 为了方面,就设置一个map,每一个位置,页面名称与这串系统给随机数的,关联起来,一一对应,你每刷新一次,则更新这串随机数,抛弃旧的随机数
// map中的存储也会覆盖这个随机数
// 下面的算法实质是上,把页面注册到这个map列表之中
public void getwebindex(String webindex) {
WebContext wctx = WebContextFactory.get();
ScriptSession sessions = wctx.getScriptSession();
scrSessionMap.put(webindex, sessions);
}
// 此乃发送方法,前端送来接受者的页面表示,与消息
public void send(String to, String msg) {
ScriptSession sessions = scrSessionMap.get(to);
// 通过如下的两行语句打回目标页的脚本进行处理
Util utilAll = new Util(sessions);
utilAll.addFunctionCall("rec", msg);
}
}
或许单看上述代码有写抽象,但请配合前端页面dwrsend.html与dwrec.html阅读,你会发现,这段代码就是那回事~
3.dwrsend.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>dwrsend</title>
<!-- 请注意head部分,头两项是必须引入的,第三行是由于dwr.xml中声明了javascript=aaa,所以必须这样引入aaa.js -->
<script type='text/javascript' src='dwr/engine.js'></script>
<script type='text/javascript' src='dwr/util.js'></script>
<script type='text/javascript' src='dwr/interface/aaa.js'></script>
</head>
<!-- body部分很简单,一个标题,一个对话框,一个一点击就请求go()函数的按钮 -->
<body>
<h3>
dwrsend
</h3>
<input type="text" id="mytext" />
<input type="button" οnclick="go()" value="go" />
</body>
</html>
<script>
/*此乃一载入页面就执行的javascript主函数*/
window.onload = function() {
/*初始化dwr的必须脚本*/
dwr.engine.setActiveReverseAjax(true);
/*把本页拉去hello.java的getwebindex方法进行注册,声明自己的页面标识是dwrsend*/
aaa.getwebindex("dwrsend");
}
function go(){
/*text就是id为mytext文本框里面输入的内容*/
var text=document.getElementById("mytext").value;
/*调用的hello.java中的send方法,传入dwrrec与text参数*/
aaa.send("dwrrec", text);
}
</script>
4.dwrrec.html
hello.java中的public void send(String to, String msg) {}方法中的ScriptSession sessions = scrSessionMap.get(to);Util utilAll = new Util(sessions);两行语句与dwrsend.html中给to形式参数传递的"dwrrec"奠定了,hello.java处理完的结果,会扔到页面标识为"dwrrec"页面下的脚本处理
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<!-- 请注意head部分,头两项是必须引入的,第三行是由于dwr.xml中声明了javascript=aaa,所以必须这样引入aaa.js -->
<title>dwrrec</title>
<script type='text/javascript' src='dwr/engine.js'></script>
<script type='text/javascript' src='dwr/util.js'></script>
<script type='text/javascript' src='dwr/interface/aaa.js'></script>
</head>
<!-- body部分很简单,一个标题,一个p标签 -->
<body>
<h3>
dwrrec
</h3>
<p id="rectext"></p>
</body>
</html>
<script>
/*此乃一载入页面就执行的javascript主函数*/
window.onload = function() {
/*初始化dwr的必须脚本*/
dwr.engine.setActiveReverseAjax(true);
/*把本页拉去hello.java的getwebindex方法进行注册,声明自己的页面标识是dwrrec*/
aaa.getwebindex("dwrrec");
}
function rec(bbb){
/*bbb是hello.java中public void send(String to, String msg){}方法中的utilAll.addFunctionCall("rec", msg);语句,扔过来的msg参数,msg参数放到本页的js脚本中的rec函数处理*/
document.getElementById("rectext").innerHTML=bbb;
}
</script>
至此,整个dwr工程的开发完毕~也不简单,但是思维上理解之后,就完全不难了。