Dwr 实例教程

前端之家收集整理的这篇文章主要介绍了Dwr 实例教程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处、作者信息和本人声明。否则将追究法律责任。
作者: 永恒の_☆地址: http://www.jb51.cc/article/p-twqllcqt-bhs.html

一、Dwr的介绍

Dwr 简称 Direct Web Remoting ,它是一个 Java Ajax远程调用的框架,利用这个框架开发可以让Ajax开发变得非常简单、快捷。 Dwr框架与匈奴开发人员在客户端都过javascript代码调用服务器段的java方法,这都依靠于服务器上运行的Dwr核心Servlet负责处理客户端的请求,将客户端请求委托到实际的java 对象中进行处理,并将结果返回给客户端。 另外Dwr能够很好的与spring集成,直接调用spring中注入的bean。


二、Dwr的准备条件

dwr2.0.jar 下载地址: http://download.csdn.net/detail/ch656409110/5894411

commons-logging.jar(查看源码可以看到Dwr运行时依赖于common-logging库)


三、Dwr执行的流程

1、首先客户端发送一个javascript的请求,dwr识别该请求之后会将请求委托到Dwr中和核心Servlet;

2、核心Servlet 会根据请求的对象以及方法去WEB-INF 下的dwr.xml中找到具体的关联对象;

3、如果满足调用的条件,那么服务器会执行该方法,并返回对应的结果,这里返回的结果会被客户端发送请求的回调函数接收;

4、客户端收到返回结果之后,做出对应的处理,整个请求结束。


四、Dwr的案例讲解

1、使用Dwr做一个简单的demo

<1>、建立Web 工程,添加Dwr的支持,这里以现有的支持struts2为基础的项目为例;

<2>、添加dwr配置文件,必须放在WEB-INF的根目录下,具体如下:

  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <!DOCTYPEdwrPUBLIC
  3. "-//GetAheadLimited//DTDDirectWebRemoting3.0//EN"
  4. @H_403_101@ "http://getahead.org/dwr/dwr30.dtd">
  5. <dwr>
  6. @H_403_101@ <allow>
  7. <createcreator="new"javascript="dwrDate">
  8. @H_403_101@ <paramname="class"value="java.util.Date"></param>
  9. </create>
  10. @H_403_101@ </allow>
  11. </dwr>

根目录是<dwr>标签,里面的<allow>表示允许的方法列表,配置每一个对象都是<create>来区分的。

creator:表示创建方式,取值有new,bean等等,其中new表示新建,bean表示取现有的对象。

javascript:表示在js客户端调用的对象引用,比如这里配置的对象是java.util.Date,那么dwrDate 就是创建的对象引用,等价于java.util.Date dwrDate = new java.util.Date();

<create>里面的<param> 表示指定创建对象的声明;

name:表示声明的name的形式;

value:表示根据name绑定的具体值;

name取值有class,beanName等等,其中name="class"表示value中绑定的是类的完整限定名,name="beanName"表示value绑定的是spring中注入的对象的引用。

<3>、修改web.xml 配置文件,配置Dwr的核心servlet,具体如下:

?
    <!--配置dwr框架的核心servlet--> @H_403_101@ <servlet>
  1. <servlet-name>dwr</servlet-name>
  2. @H_403_101@ <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
  3. <!--添加调试模式,方便调试方法,正式发布的时候可以改为false默认值为fasle-->
  4. @H_403_101@ <init-param>
  5. <param-name>debug</param-name>
  6. @H_403_101@ <param-value>true</param-value>
  7. </init-param>
  8. @H_403_101@ </servlet>
  9. <servlet-mapping>
  10. @H_403_101@ <servlet-name>dwr</servlet-name>
  11. <url-pattern>/dwr/*</url-pattern>
  12. @H_403_101@ </servlet-mapping>

如上配置,所有以/dwr/ 结尾的请求都会被DwrServlet匹配 执行相应的请求。

好了,接下可以调试我们的Dwr了,启动服务器,打开浏览器输入:http://localhost:8080/house/dwr (这个是Dwr入口,将展示所有在dwr.xml中配置完的对象列表,点击进去会看到 配置的对象允许方法方法等)

结果报错,具体如下:

严重: Allocate exception for servlet dwr
org.xml.sax.SAXException: Failed to resolve: arg0=-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN arg1=http://getahead.org/dwr/dwr30.dtd

这是因为添加的jar包是2.0版本的,但是却引用了3.0的dtd文件,所以报错了,改为如下配置即可:

?
    <!DOCTYPEdwrPUBLIC"-//GetAheadLimited//DTDDirectWebRemoting2.0//EN"
  1. "http://www.getahead.ltd.uk/dwr/dwr20.dtd">
  2. @H_403_101@ <dwr>
  3. <allow>
  4. @H_403_101@ <createcreator="new"javascript="dwrDate">
  5. <paramname="class"value="java.util.Date"></param>
  6. @H_403_101@ </create>
  7. </allow>
  8. @H_403_101@ </dwr>

修改之后再次打开dwr地址,又报错了:

Struts Problem Report

Struts has detected an unhandled exception:
Messages:
There is no Action mapped for namespace / and action name dwr.
Stacktraces
There is no Action mapped for namespace / and action name dwr. - [unknown location]

意思就是说找不到namespace为 / 并且action名称为dwr的Action 类,这里是因为struts2 的核心控制器StrutsPrepareAndExecuteFilter,拦截了所有的请求去找action方法了,所以404

现在要在struts.xml中过滤掉所有的以 /dwr/ 这样子结尾的请求才行,添加一个不包括访问的参数即可,具体如下:

?
    <!--核心控制器在处理页面跳转时是拦截所有跳转,当跳转到house/dwr/下进行方法测试时,struts核心控制把 @H_403_101@ 它看成是一个action,所以就跳不过去了,可以通过配置一个常量struts.action.excludePattern,值里面用
  1. 正则表达式匹配,
  2. @H_403_101@ .表示除了换行以外其他所有的字符
  3. *表示字符或表达式出现的次数零次或多次-->
  4. @H_403_101@ <constantname="struts.action.excludePattern"value="/dwr.*"></constant>
保存struts.xml 再次启动服务器,打开地址,效果如下:


这个就表示 我们在dwr.xml中配置的dwrDate对象成功了。点击dwrDate超链接效果如下:


这里面列出了所有的java.util.Date中所有允许访问的放,点击每一个execute 表示测试该方法。。

ok....现在在Action类中添加一个方法dwrDemo() 并且对应创建一个dwrDemo.jsp 专门用于测试dwr。

具体如下:

?
    <%@pageimport="java.util.List"%> @H_403_101@ <%@pagelanguage="java"contentType="text/html;charset=UTF-8"%>
  1. <%@includefile="/common/taglib.jsp"%>
  2. @H_403_101@ <!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <htmlxmlns="http://www.w3.org/1999/xhtml">
  4. @H_403_101@ <head>
  5. <Metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/>
  6. @H_403_101@ <title>永恒租房-首页</title>
  7. <!--这三个js导入项必不可少-->
  8. <!--每一个对象都会有以一个对象为名称的那个js库-->
  9. <scripttype='text/javascript'src='${ctx}/dwr/interface/dwrDate.js'></script>
  10. <!--Dwr引擎库-->
  11. <scripttype='text/javascript'src='${ctx}/dwr/engine.js'></script>
  12. <!--Dwr工具库-->
  13. <scripttype='text/javascript'src='${ctx}/dwr/util.js'></script>
  14. @H_403_101@ <script>
  15. window.onload=function(){
  16. @H_403_101@ //输出当前时间
  17. //需要说明的是,如果在客户端输出dwrDate对象将返回undefined,除非调用完整的函数(也就是服务器端的方法)才会调用成功
  18. @H_403_101@ //客户端接收参数的方法都是通过回调函数获取的。
  19. dwrDate.getYear(function(data){
  20. @H_403_101@ //在回调函数里面不能使用document.write("")输出,因为第一次输出之后,浏览器会一直处于加载的状态,f12看不出在加载什么,然后后面的document.write("")也不会再执行了。
  21. document.getElementById("showTime").innerHTML+=1900+data+"年";
  22. @H_403_101@ });
  23. dwrDate.getMonth(function(data){
  24. @H_403_101@ document.getElementById("showTime").innerHTML+=1+data+"月";
  25. });
  26. @H_403_101@ dwrDate.getDate(function(data){
  27. document.getElementById("showTime").innerHTML+=data+"日";
  28. @H_403_101@ }; @H_403_101@ </script>
  29. </head>
  30. @H_403_101@ <body>
  31. <divid="showTime">当前时间:</div>
  32. @H_403_101@ </body>
  33. </html>
在地址栏输入: http://localhost:8080/house/house/dwrDemo.action ,结果alert了三个文本都是 Session Error 。

这里需要在dwrServlet中添加参数crossDomainSessionSecurity,具体配置如下:

?
    <!--这个crossDomainSessionSecurity必须配置,应该是跨区域提交设置,默认是ture, @H_403_101@ 如果不设置为false就会报错:SessionError-->
  1. <init-param>
  2. @H_403_101@ <param-name>crossDomainSessionSecurity</param-name>
  3. <param-value>false</param-value>
  4. @H_403_101@ t;/init-param>

然后再次重启服务器打开dwrDemo页面效果如下:


2、使用Dwr服务器对象配置允许访问的方法

接下来,新创建一个类,里面有setValue(),getValue()等等方法,具体如下:

[java] ?
    privateStringvalue="default"; @H_403_101@
  1. publicStringgetValue(){
  2. @H_403_101@ returnvalue;
  3. }
  4. @H_403_101@ publicvoidsetValue(Stringvalue){ @H_403_101@ this.value=value;
  5. }

然后在dwr.xml中自己再配置一个自己定义的对象,具体如下:

? @H_743_1404@
    <createcreator="new"javascript="houseDwrBiz"> @H_403_101@ <paramname="class"value="com.struts2.biz.impl.HouseBizImpl"></param>
  1. <includemethod="getValue,setValue"/>
  2. @H_403_101@ <excludemethod="getListPage"/>
  3. </create>
配置文件中 ,新添加了 <include>和<exclude>标签,他们分别表示该对象中允许客户端访问的方法,和不允许访问的方法

好了,然后打开服务器 启动调试窗口,结果直接报错,具体如下:

[ERROR] [http-apr-8080-exec-5] - Failed to add creator: type=new,javascript=houseDwrBiz
java.lang.IllegalArgumentException: The Creator houseDwrBiz uses mixed include and exclude statements

意思是说 <include>和<exclude>不能共存,也就是一山不容二虎。

并且实践证明,<include>标签里面只能绑定一个方法,如果配置了<include>那么其他就都不允许访问,如果配置了<exclude>那么其他的方法就都允许访问。

是否允许访问可以在调试页面中的方法下面注明,如下:

(Warning: getListPage() is excluded: Method access is denied by rules in dwr.xml. Seebelow)

这样子的话 每允许访问一个方法就要加一个<inclue>标签,具体如下:

?
    <includemethod="getValue"/> @H_403_101@ <includemethod="setValue"/>
  1. <!--<excludemethod="getListPage"/>-->
  2. @H_403_101@ </create>

添加测试的页面,具体如下:

?
    <scripttype='text/javascript'src='/house/dwr/interface/houseDwrBiz.js'></script>
  1. <!--Dwr引擎库-->
  2. @H_403_101@ <scripttype='text/javascript'src='${ctx}/dwr/engine.js'></script>
  3. <!--Dwr工具库-->
  4. @H_403_101@ <scripttype='text/javascript'src='${ctx}/dwr/util.js'></script>
  5. <script>
  6. @H_403_101@ //这里故意命名为setValuegetValue,看是否与houseDwrBiz冲突,事实发现没有问题
  7. functionsetValue(){
  8. @H_403_101@ varvalue=document.getElementById("set").value;
  9. houseDwrBiz.getValue(value,function(data){
  10. @H_403_101@ //setsuccess
  11. }
  12. functiongetValue(){
  13. @H_403_101@ houseDwrBiz.getValue(function(data){
  14. //getsuccess
  15. @H_403_101@ document.getElementById("get").value=data;
  16. </script>
  17. @H_403_101@ </head>
  18. <body>
  19. @H_403_101@ <divid="showTime">当前时间:</div>
  20. <inputid="set"value=""/><inputtype="button"value="setValue"onclick="setValue()"/><br/>
  21. @H_403_101@ <inputid="get"value=""/><inputtype="button"value="getValue"onclick="getValue()"/>
  22. @H_403_101@ </body> @H_403_101@ </html>

实践证明,每一个houseDwrBiz 发出的请求都是多例的,都会重新产生一个新的实例,以为上面例子 我先setValue ,然后在getValue 得到依旧是default。


3、使用Dwr转换器保存对象以及接收对象集合

上面都是一些非常简单的例子,如果涉及比如复杂的需求,比如接受一个集合 或者保存一个对象到服务器呢?接下里简单介绍下如何去做。

HouseBizImpl 添加方法,具体如下:

?
    publicintsaveDwrHouse(Househouse){ @H_403_101@ returnhouse==null?0:1;//1成功,0失败
  1. publicList<House>getDwrHouseList(intdwrId){
  2. @H_403_101@ List<House>houseList=newArrayList<House>();
  3. Househouse=newHouse();
  4. @H_403_101@ if(dwrId==1){
  5. house.setId(1);
  6. @H_403_101@ house.setDescription("好房子便宜出租!");
  7. house.setPubDate(newDate());
  8. @H_403_101@ house.setTitle("便宜的房子");
  9. house.setContact("132312312");
  10. @H_403_101@ }else{
  11. 2);
  12. @H_403_101@ house.setDescription("好房子确实很便宜!");
  13. house.setTitle("全区最低价格特价出租");
  14. house.setContact("123456789");
  15. @H_403_101@ houseList.add(house); @H_403_101@ returnhouseList; @H_403_101@ }
同时,dwr.xml也要把这两个方法 包含进去,否则不允许访问。具体如下:

?
    <includemethod="saveDwrHouse"/>
  1. <includemethod="getDwrHouseList"/>
  2. @H_403_101@ <convertconverter="bean"match="com.struts2.entity.House"></convert>
在<create>标签的同级目录多了一个<convert>转换器标签

converter:转换器类型,一般是javabean,直接指定converter="bean"就好了;

match:表示转换器匹配的类的完整限定名。

配置完毕之后,然后再在dwrDemo.jsp调用,具体如下:

[javascript] ?
    //得到house集合 @H_403_101@ houseDwrBiz.getDwrHouseList(1,function(data){
  1. if(data!=null){
  2. @H_403_101@ for(vari=0;i<data.length;i++){
  3. document.getElementsByTagName("body")[0].innerHTML="id:"+data[i].id+"。<br/>"
  4. @H_403_101@ +"description:"+data[i].description+"。<br/>"
  5. +"attachUrl:"+data[i].attachUrl+"。<br/>"
  6. @H_403_101@ +"contact:"+data[i].contact+"。<br/>"
  7. +"floorage:"+data[i].floorage+"。<br/>";
  8. //保存house对象
  9. @H_403_101@ varhouse={id:111,contact:"12345"};
  10. houseDwrBiz.saveDwrHouse(house,function(data){
  11. @H_403_101@ alert(data==1?"添加成功":"添加失败");
  12. });
测试可知 getDwrHouseList返回的是一个json格式的集合,同样保存house对象的时候也要手动封装数组传递。


五、Dwr的js库

在前面的例子中,有引用三个核心的js库,具体如下:

?
    <scripttype='text/javascript'src='/house/dwr/interface/houseDwrBiz.js'></script> @H_403_101@ <scripttype='text/javascript'src='${ctx}/dwr/util.js'></script>
houseDwrBiz.js 是Dwr根据dwr.xml中配置的对象来动态生成的js库,里面封装的就是所有允许调用的js函数,具体如下:

?
    //Provideadefaultpathtodwr.engine @H_403_101@ if(dwr==null)vardwr={};
  1. if(dwr.engine==null)dwr.engine={};
  2. @H_403_101@ if(DWREngine==null)varDWREngine=dwr.engine;
  3. if(houseDwrBiz==null)varhouseDwrBiz={};
  4. houseDwrBiz._path='/house/dwr';
  5. @H_403_101@ houseDwrBiz.getValue=function(callback){
  6. dwr.engine._execute(houseDwrBiz._path,'houseDwrBiz','getValue',callback);
  7. @H_403_101@ houseDwrBiz.setValue=function(p0,callback){
  8. 'setValue',p0,callback);
  9. houseDwrBiz.saveDwrHouse=function(p0,callback){
  10. 'saveDwrHouse',226)"> houseDwrBiz.getDwrHouseList=function(p0,'getDwrHouseList',226)"> }

所以,现在对Dwr调用方式一目了然了。

engine.js对Dwr非常的重要,它是Dwr客户端的核心,用来把动态声声称的Javascript对象转换成服务器端的java对象。

并且 在上面的houseDwrBiz.js中 每一个函数都是通过dwr.engine._execute()这个函数调用后台服务器方法的,所以用到Dwr的地方就要用到它。

util.js这个是Dwr提供的工具类,里面提供了一些javascript的封装函数以及选择器,要是有什么不会的可以直接查看它的源码。

下面例子讲解Dwr操作Select控件和表格如下:

?
    //获取对象直接使用$("id")不用像以前一样使用document.getElementById("id")那么麻烦
  1. $("showTime").innerHTML="当前时间:"+newDate();
  2. @H_403_101@ //对象赋值
  3. $("set").value="12345";
  4. @H_403_101@ //util.js中的针对表单控件赋值和取值
  5. dwr.util.setValue("showTime","67890");
  6. @H_403_101@ alert(dwr.util.getValue("showTime"));
  7. //使用dwr.util.removeAllOptions("id")删除select控件中所有的option元素
  8. @H_403_101@ //至于为什么要这么用在util.js中有清晰的函数说明
  9. dwr.util.removeAllOptions("slt");
  10. @H_403_101@ };
  11. //添加Select控件的option元素,需要传递json格式的对象
  12. functionaddOption(){
  13. @H_403_101@ vararray=[{id:"a",name:"aaa"},
  14. {id:"b",name:"bbb"},
  15. @H_403_101@ {id:"c",name:"ccc"}
  16. ];
  17. @H_403_101@ //这里面参数必须都要指定,id,封装的数组,value,name如果不指定value,name将添加的全是[object,Object]
  18. dwr.util.addOptions("slt",array,"id","name");
  19. @H_403_101@ //删除table中所有的rows,只会留一个空的table标签
  20. functionremoveAllRows(){
  21. @H_403_101@ dwr.util.removeAllRows("tbl");
  22. //添加表格中的row,同时也需要传递json格式的对象
  23. functionaddRows(){
  24. @H_403_101@ vararray=[{id:"b",name:"ccc"},226)"> {id:"d",name:"ddd"}
  25. //从上面的array的数组中封装cellFuncs这样一个函数组,用于从传递的行数据中提取单元格数据
  26. varcellFuncs=[
  27. @H_403_101@ function(data){return"<ahref='javascript:alert(\""+data.id+"\")'>"+data.id+"</a>";},226)"> function(data){return"<ahref='javascript:alert(\""+data.name+"\")'>"+data.name+"</a>";}, @H_403_101@ function(data){return"<ahref='javascript:alert(\"test\")'>测试</a>";}
  28. //添加一行,然后escapeHtml表示是否将加入的元素按文本输出还是按html格式输出,默认是true,按文本输出
  29. dwr.util.addRows("tbl",cellFuncs,{escapeHtml:false});
  30. @H_403_101@ <inputid="get"value=""/><inputtype="button"value="getValue"onclick="getValue()"/><br/>
  31. <selectid="slt">
  32. @H_403_101@ <optionvalue="1">111</option>
  33. <optionvalue="2">222</option>
  34. @H_403_101@ <optionvalue="3">333</option>
  35. </select>
  36. @H_403_101@ <inputtype="button"value="addOption"onclick="addOption()"/>
  37. <tableborder="1"width="50%"id="tbl">
  38. @H_403_101@ <tr>
  39. <td>id</td>
  40. @H_403_101@ <td>name</td>
  41. <td>操作</td>
  42. @H_403_101@ </tr>
  43. <tbodyid="tbl">
  44. @H_403_101@ <td>a</td> @H_403_101@ <td>aaa</td>
  45. <td><ahref="javascript:alert('test')">测试</a></td>
  46. @H_403_101@ </tbody> @H_403_101@ </table>
  47. <inputtype="button"value="removeAllRows"onclick="removeAllRows()"/>
  48. @H_403_101@ <inputtype="button"value="addRows"onclick="addRows()"/><br/>
  49. </html>
效果图如下图所示:


六、Dwr 与 Jquery 的区别

Dwr 是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,因为它是java特有的框架,所以可以帮助开发人员开发包含AJAX技术的网站,它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA方法,就像它就在浏览器里一样。   

而Jquery是一个优秀的Javascrīpt框架。是一个js库,它兼容CSS3,还兼容各种浏览器 (IE 6.0+,FF 1.5+,Safari 2.0+,Opera 9.0+扽等)。jQuery使用户能更方便地处理HTML documents、DOM、events、实现动画效果,并且方便地为网站提供AJAX交互,而且还有许多成熟的插件可供选择。jQuery能够使用户的html页保持代码和html内容分离,更加丰富和友好的展示Jquery带给我们的好处。

另外Dwr和Jquery都可以发送Ajax请求,尽管语法不同,另外他们操作对象并不兼容,因为他们都是通过$符号获取对象的,那么怎么区分,可以这样,具体如下:

?
    //解除jQuery的别名$,默认使用jQuery或者引用对戏那个jq都可以重新操作jquery元素。 @H_403_101@ varjq=$.noConflict();
  1. alert(jQuery("#showTime").html());


七、Dwr 与 Spring 集成

如何项目中用到了Spring,那么之前在dwr.xml配置的对象其实可以交给Spring去管理的,实现的方式很简单,修改原先配置的houseDwrBiz 对象的配置,改为如下配置即可:

?
    <createcreator="spring"javascript="houseDwrBiz"> @H_403_101@ <paramname="beanName"value="houseBizImpl"></param>
  1. <convertconverter="bean"match="com.struts2.entity.House"></convert>

修改的地址有两个,原先<create>中的creator 都是“new”,现在交给spring去管理了,所以是"spring",另外子元素<param>中的name原先是new 所以每次调用都会产生一个新的实例,现在换成beanName,表示去spring中注入的对象中找到houBizImple 直接拿来用。

这样 有一个好处,保证之前的多例访问模式变成单例了,从而节省每次调用都要创建对象的性能开销。


现在对Dwr一定已经有一定的理解,这些小demo虽然非常简单,即使不使用强大的Dwr也可以非常容易的实现上面的功能,但是这些小程序是为了更加友好的体验和使用Dwr框架给我们带来的好处。

猜你在找的Ajax相关文章