一、概念

DWR(Direct Web Remoting),中文翻译成“直接Web远程控制”。我认为就是将AJAX作了一次封装,并提供与服务器端Java组件进行交互的一个组件。在其官方网站(http://getahead.ltd.uk/dwr)上说得很清楚,“DWR is Easy Ajax for Java”。DWR允许客户端的javascript与服务器端的Java进行交互,并根据其交互结果,控制网页的表现。

说的更明白一些,实际上我的感觉DWR就是在客户端用Javascript来调用服务器端的Java服务。

技术上,DWR是基于Java,自动生成javascript代码发送到客户端,而这些javascript代码则使用AJAX技术,接受用户请求,与服务器交互。

二、配置

要使用DWR,需要有两个配置(当然了,前提要将dwr.jar放在classpath中):

 1.在web.xml中加入如下Servlet信息:

 1 < servlet >
 2     < servlet-name > dwr-invoker </ servlet-name >
 3     < display-name > DWR Servlet </ display-name >
 4     < servlet-class > uk.ltd.getahead.dwr.DWRServlet </ servlet-class >
 5     < init-param >
 6      < param-name > debug </ param-name >
 7      < param-value > true </ param-value >
 8     </ init-param >
 9    </ servlet >
10
11    < servlet-mapping >
12     < servlet-name > dwr-invoker </ servlet-name >
13     < url-pattern > /dwr/* </ url-pattern >
14    </ servlet-mapping >


如此,则将所有的/dwr/开头的URL请求,影射到dwr-invoker这个Servlet去处理。

 2.在web.xml的同一个目录下,建立dwr.xml配置文件,在其中配置dwr组件信息,具体内容将在使用一节中讲到。

三、使用

 1.一个简单的例子:

  例如服务器端提供了一个POJO,叫做com.lingdot.dwrtest.TestBean,代码如下:

 

   package  com.lingdot.dwrtest;

  
public   class  TestBean
  {
   
public   int  sum( int  a, int  b)
   {
    
return  a + b;
   }
  }

 

  在dwr.xml中,作如下配置:

   < dwr >
    
< allow >
   
< create  creator ="new"  javascript ="Demo" >
     
< param  name ="class"  value ="com.lingdot.dwrtest.TestBean" />
   
</ create >
    
</ allow >
  
</ dwr >

 

  Reload这个应用,然后在浏览器中打开URL:http://localhost:8080/dwr/(假设当前应用是Tomcat的ROOT应用)。


 
 这个页面将dwr.xml中配置的Java服务都列了出来。当前我们只配置了一个TestBean。点击TestBean,出来的页面会教你如何调用这个Bean的方法。
 
 例如我们的TestBean提供了int sum(int a,intb)这样的方法,那么,在页面上:

1.包含如下三个js:

< script  type ='text/javascript'src='/DWR/dwr/interface/Demo.js'></script>
<script type ='text/javascript'  src ='/DWR/dwr/engine.js'></script>
<script type ='text/javascript'  src ='/DWR/dwr/util.js'></script>

 

其中第三个js是可选的,一个工具集。
 2.写如下代码:
  

< input  type ="button"  value ="1+2=?"  onclick ="Demo.sum(1,2,reply0);" />
< div  id ="m" ></ div >
< script >
 var reply0 = function(data)
    {
      if (data != null && typeof data == 'object')
alert(DWRUtil.toDescriptiveString(data, 2));
      else
DWRUtil.setValue('m', DWRUtil.toDescriptiveString(data, 1));
    }
</ script >

 

注意,其中button上的onclick事件调用的是Demo对象的sum方法。而Demo对象是由我们在dwr.xml中配置的一个create节点中写的javascript=”Demo”属性而来的。

再注意,Demo的sum方法其实就是我们的TestBean的sum方法,但是,在参数列表的最后,新加了一个变量,叫做reply0。紧接着在下面的script代码中我们定义了这个reply0是一个函数,这个函数的功能就是如果所提供的data不为空,那么,就把它显示到一个id为”m”的html元素内部。而这个id为“m”的元素在文档中已经定义为一个div元素。由此,Demo的sum方法执行的时候实际上是调用服务器端的TestBean的sum方法,并返回结果,作为data参数,传递给reply0方法去处理,而处理的结果,就是在id=”m”的div元素内部显示出来。

四、需要注意的两个问题

 1. Warning: No Converter for XXX.
dwr.xml does not have an allow entry that enables conversion of this type to Javascript. The most common cause of this problem is that XXX is a java bean and bean marshalling has not been enabled. Bean marshalling is disabled by default for security reasons.
To enable marshalling for a given bean add the following line to the allow section of your dwr.xml file:
<convert converter="bean" match="XXX"/>
It is also possible to enable marshalling for an entire package or hierachy of packages using the following:
<convert converter="bean" match="package.name.*"/>

2.不要重载方法

五、一些方法

1. DWRUtil.setValue('d0', DWRUtil.toDescriptiveString(data, 1));

DWRUtil.setValue() is a utility that takes the data you pass in the second parameter and works out how to fit it to go into the HTML element specified by id in the first parameter. This function is one of several neat Javascript utilities that make working with DWR much easier.

第一个参数是要显示内容的元素的id,如上面的例子中的m是一个div的id,第二个参数是要显示的内容
2. 方法参数以及回调函数的几种写法:
Demo.sum(1,2,{callback:function(str) { alert(str); },
  timeout:5000,
  errorHandler:function(message) { alert('Oops: ' + message); }
});

Remote.getData(42, function(str) { alert(str); });
3. 建立javascript对象,对应java的对象,例如:

在Java中有一个Remote类,其中的方法setPerson参数是Person类的一个对象,Java代码如下:

public   class  Remote {
  
public   void  setPerson(Person p) {
    
this .person  =  p;
  }
}

public  Person {
  
private  String name;
  
private   int  age;
  
private  Date[] appointments;
  
//  getters and setters 
}



那么,在Javascript中可以这样写:

 4. DWRUtil.useLoadingMessage(); 显示正在更新数据的标志

var p  =  {    // 建立与java的Person类对应的js对象
  name: " Fred Bloggs " ,
  age:
42 ,
  appointments:[ 
new  Date(),  new  Date( " 1 Jan 2008 " ) ]
};
Remote.setPerson(p);