网络上的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" onclick="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工程的开发完毕~也不简单,但是思维上理解之后,就完全不难了。