DWR
DWR的作用:DWR是一个可以允许你去创建AJAX WEB站点的JAVA开源库。它可以让你在浏览器中的Javascript代码调用Web服务器上的Java代码,就像在Java代码就在浏览器中一样。
其中的KnowDAO类是实现了CRUD方法的dao类,返回一个字符串,内容是当前时间和数据库中的数据数量。注:别忘了写getter,setter方法。
DWR的配置:
web.xml:首先要在你的web.xml中加入dwr的配置代码,代码如下:.
其中<init-param>中配置了debug的值,表示可以进入调试模式,其他都是必须有的
dwr.xml:要建立一个dwr.xml的配置文件,这个文件放在你的项目的根目录下。和你的web.xml放在一起。在demo中我的代码如下:
其中<dwr>中的部分就是dwr的配置,<dwr>中<allow>标签中定义了DWR能够创建和转换的类.<create>中的create属性有很多类型,这里使用的是spring表示整合spring。
javascript属性的值是DwrTime是在js的页面中使用的,类似于beans.xml中,bean id的作用
不同的是bean id的值作为一个对象的实例,可以直接使用在java中,而javascript属性是直接使用在js中。
<param>标签中的值表示的是与beans.xml注入的哪个实例相对应,name属性是固定的表示这个属性是与bean id相关,value属性和bean id的值是相同的.beans.xml中的注入文件如下:
<include>标签表示的是类中那些方法可以在js中使用,如果不想让某些方法在js被调用,
那么就不要include它,注意method属性的值可以是”*”,用来表示所有方法.
PS:除了include标签以外,还可以用exclude 标签来声明,exclude表示的是不能使用的方法,凡是没声明的就可以使用,exclude不推荐使用。
beans.xml中的配置:
在beans.xml中将要远程调用的类作为bean来注入,如上图所示。它与drw.xml中的相关属性对应不再重复
js文件中的使用
做完以上工作我们可以在js中使用它远程调用的方法了如下所示:
图中前3行代码的意思分别是:
<script type='text/javascript' src='/somcdemo/dwr/interface/DwrTime.js'></script>
表示引入/somcdemo/dwr/interface/DwrTime.js 这个js是根据你所写的类自动生成的,也是必须引入的。
<script type='text/javascript' src='/somcdemo/dwr/engine.js'></script>
表示引入/somcdemo/dwr/engine.js 这个js是dwr的jar文件中自带的,如果你想程序正常运行就必须引入。
<script type='text/javascript' src='/somcdemo/dwr/util.js'></script>
表示引入/somcdemo/dwr/util.js,这个js也是dwr的jar文件中自带的,它提供了一些好用的方法,如果你想使用也要引入.
接下来定义了3个方法:
第1个方法CreateWindow与dwr无关。
第2个方法是getTime方法,在调用的时候使用了DwrTime(它就是dwr.xml中javascript属性中那个),它就是DwrTime类的实例。DwrTime.currentlyTime("本次查询时间:",callBackTime);就是调用了DwrTime的currentlyTime方法,currentlyTime方法有两个参数,第一个参数是”本次查询时间”,这个字符串,它是作为currentlyTime方法的参数使用的。
第2个参数callBackTime是回调方法的名字,当 currentlyTime方法运行完毕后,返回一个值,把这个值作为参数,调用callBackTime方法(所以callBackTime方法必须有个参数). callBackTime方法就是回调方法。
注意:回调方法名不是固定的.自己定义
PS:本文档主要讲了DWR与SPRING的整合使用(初步),DWR还有很多别的标签,和高深的应用技巧,技术浅薄不能一一介绍,推荐观看DWR中文文档.pdf
11.1.2 DWR使用入门
有两种方式可以开始DWR的应用。一种是直接从其官方网站下载DWR的Web应用示范包,这是一个war的部署包,从中可以对DWR的应用效果及其部署方式有一个大概的了解。不过这种方式无法详细掌握如何将DWR与Web应用程序紧密集成。另外一种方式是根据DWR官方开发文档的讲解,通过一步步的部署和配置,将DWR集成到Web应用程序中。本节通过简单的示范和一个例子来讲述DWR的部署和集成。
DWR采用一个Java Servlet来处理请求并将响应结果发送给浏览器,这个Java Servlet需要加入到Java Web应用程序的部署描述文件web.xml。其次,它通过一个自定义的部署描述文件dwr.xml来控制Java对象与Javascript的转化。下面通过五步简单的配置,将DWR部署到2.4节创建的开发项目中。
第一步:安装jar开发包。
从DWR官方网站http://www.getahead.ltd.uk/dwr/下载DWR的开发包。这里采用DWR1.0,它是一个简单的名为dwr1.0.jar开发包。将这个开发包放到{APPLICATION_ WEB_HOME} /WEB-INF/lib目录下。如果使用DWR1.1,则下载的应该是DWR1.1的开发包。这个开发包中包含了DWR运行所需的全部Java类及相应的API。dwr1.0.jar也可以从随书光盘jar lib目录中找到。
修改{APPLICATION_WEB_HOME}/WEB-INF目录下的web.xml,将下列代码添加到web.xml的适当位置。
例程11-1 为web.xml添加DWR映射
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<servlet>映射部分应该紧随web.xml中的其他<servlet>映射,<servlet-mapping>则紧随<servlet-mapping>部分。
这段部署描述告诉Web应用程序,全部以“/dwr/”起始的URL所指向的请求都交给uk.ldt.getahead.dwr.DWRServlet这个Java Servlet来处理。
第三步:创建dwr.xml
在{APPLICATION_WEB_HOME}/WEB-INF目录下创建dwr.xml部署描述文件,其代码例程11-2所示。
例程11-2 DWR部署描述文件dwr.xml
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
</allow>
</dwr>
这个XML文档中用到了其对应的DTD文档,顶部的文档声明指明当前用到的是DWR1.0版本。如果使用DWR1.1,则应该相应地修改这个XML文档的文档声明。
这个部署描述文件定义什么样的Java 类可以被DWR应用创建并通过Javascript远程调用。在上面的部署描述中,定义了可以被DWR创建的Java类java.util.Date,并给这个类赋予一个Javascript名称JDate。通过修改dwr.xml,也可以将自定义的Java类暴露给Javascript远程调用。
需要注意的是,dwr部署描述为远程Java类拟定的Javascript名称还是有些限制的。
避免使用Javascript关键字或者保留字,因为这些用Javascript关键字或者保留字命名的方法会自动执行。大部分的Javascript关键字或者保留字也是Java的关键字或者保留字,比如,“try()”不是一个合法的命名。不过还是有一部分的Javascript关键字或者保留字在Java中不被限制,比如“delete()”。
避免使用方法重载。有时候,在调用这些重载的方法会引起麻烦,因为Javascript没有像Java那样的包命名机制来支持方法重载。
第四步:测试URL,查看部署效果。
在浏览器地址栏中输入http://localhost:8080/ajaxlab/dwr,其页面效果如图11-2所示。通常,这个页面会显式在dwr.xml部署描述文件中定义的全部Java类,并且显式可以查看所有其可供远程调用的方法的列表的链接。这个页面由DWR动态创建。在本例中,页面上有一个JDate的链接,列出暴露给DWR的JDate类可供Javascript远程调用的方法。
图11-2 DWR部署效果
单击“JDate”链接,查看Javascript能够调用的java.util.JDate类的方法,其效果如图11-3所示。单击每个方法后面的“Execute”按钮,尝试执行这些方法。
java.util.Date类的相关方法已经暴露出来供Javascript远程调用。将以下的Javascript引用代码添加到JSP或者HTML文件中,就可以在JSP或者HTML文件中直接调用第四步配置所暴露的java.util.Date类的方法了。
<script language="javascript" src="/ajaxlab/dwr/interface/JDate.js"> </script>
<script language="javascript" src='/ajaxlab/dwr/engine.js'></script>
<script language="javascript" src='/ajaxlab/dwr/util.js'></script>
例程11-3展示了这个过程,调用java.util.Date类的toString()方法将当前时间打印出来。这个例子包含一个普通按钮控件和两个Javascript函数,其中一个函数doTest通过JDate.toString()调用,取得java.util.Date所表示的当前时间。第二个函数responseDate将第一个函数所取得的当前时间以弹出窗口的形式显式出来。第二个函数的名称作为第一个函数的参数,这与第5章所说的回调函数类似。具体代码如例程11-3所示,其运行效果如图11-4所示。
例程11-3 sample12_1.jsp
<%@ page contentType="text/html; charset=gb2312" errorPage="" %>
<html>
<head>
<Meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Ch11--DWR使用入门</title>
<script language="javascript" src="/ajaxlab/dwr/interface/JDate.js"></s cript>
<script language="javascript">
function doTest() {
JDate.toString(load);
}
function load(data) {
window.alert("Current Time:"+data);
</script>
</head>
<body>
<input type="button" name="count" value="cont" onClick="doTest()">
</body>
</html>
图11-4 调用JDate的Javascript方法显示当前时间
通过简单的配置,Javascript可以自由地远程调用Java对象的方法。接下来看看DWR是怎么实现上述设计的。DWR使用dwr.xml部署描述文档来定义Javascript对象和Java类之间的映射转化。首先了解一下dwr.xml这个DWR定义的部署描述文件的结构。从dwr.xml对应的DTD(http://www.getahead.ltd.uk/dwr/dwr10.dtd,版本1.0)文件中很容易知道dwr.xml的具体结构。从DWR的官方网站可以找到关于这个DTD的说明文档(http://get ahe ad.ltd.uk/dwr-demo/dtddoc/)。
所有部署描述文件的顶级根元素为dwr,其按照顺序可以包含以下三个子元素之一。
init:此元素定义那些在应用程序启动时作为DWR运行库所需的类自动加载并初始化的类。
allow:此元素定义那些允许客户端Javascript远程调用的Java类。
signatures:此元素签名必要的方法,当使用集合的时候,为转换器指定Java反射机制外的类别信息。
表11-1显示了dwr.xml的各个组成元素及其父元素、属性、子元素、用途等信息。
表11-1 dwr.xml组成元素及其属性和用途
元素名称 |
父元素 |
用 途 |
|
dwr |
|
|
dwr.xml文档的根元素 |
init |
|
dwr |
定义那些在应用程序启动时作为DWR运行库所需的类自动加载并初始化的类 |
creator |
|
init |
|
|
id |
creator |
用来惟一标识creator所创建的对象。必需属性 |
|
class |
creator |
|
converter |
|
init |
|
|
id |
converter |
用来惟一标识converter所创建的对象。必需属性 |
|
class |
converter |
|
allow |
|
dwr |
定义那些允许客户端Javascript远程调用的Java类 |
create |
|
allow |
定义允许创建的Java类,并为其指定一个Javascript名称,并定义DWR应当如何获得要进行远程的类的实例 |
|
creator |
create |
续表
用 途 |
|||
|
javascript |
create |
|
|
scope |
create |
create元素所创建的类的可用范围,默认为page。可选属性 |
param |
|
create |
指定create元素所需要的参数,比如其允许创建的Java类的名称 |
|
name |
param |
|
|
value |
param |
param元素所指定的参数值。必需属性 |
include |
|
create |
|
exclude |
|
create |
指定那些想防止被访问的方法 |
auth |
|
create |
为暴露给浏览器的方法指定允许访问的角色 |
|
method |
auth |
|
|
role |
auth |
指定允许访问的角色。必需属性 |
convert |
|
allow |
告诉DWR在服务器端Java 对象表示和序列化的Javascript之间如何转换数据类型 |
|
converter |
convert |
指定所使用的转换器的标识。必需属性 |
|
match |
convert |
|
param |
|
convert |
指定转换器所要包含的参数 |
|
name |
param |
|
|
value |
param |
param元素所指定的参数值。必需属性 |
signatures |
|
dwr |
签名必要的方法,当使用集合的时候,为转换器指定Java反射机制之外的类别信息 |
create元素告诉DWR应当公开给Ajax请求的服务器端类,并定义DWR应当如何获得要进行远程的类的实例。这里的creator属性被设置为值new,这意味着DWR应当调用类的默认构造函数(无任何参数)来获得实例。其他的可能通过代码段用Bean脚本框架(Bean Scripting Framework,BSF)来创建实例,或者通过与IOC容器Spring进行集成来获得实例。默认情况下,到DWR的Ajax请求会调用creator,实例化的对象处于页面范围内,因此请求完成之后就不再可用。本节的例子中,在无状态的JDate情况下,这样很好。
create的javascript属性指定从Javascript代码访问对象时使用的名称。嵌套在create元素内的param元素指定creator 要创建的Java类。最后,include元素指定应当公开的方法的名称。显式地说明要公开的方法是避免偶然间允许访问有害功能的良好实践(如果漏了这个元素,类的所有方法都会公开给远程调用)。反过来,则可以用exclude元素指定那些想防止被访问的方法。
create元素的creator属性可有三种选择值:new,scripted,spring。最常见的是new选择值,它代表将使用Java类默认的无参数构造方法创建类的实例对象。scripted选择值则代表允许使用一些脚本语言,比如用BeanShell来创建Java类的实例对象,这在类无法通过配置远程调用的时候特别有用。spring选择值则允许远程调用spring Bean。当需要调用包含静态(static)方法的Java类时,建议使用new选择值。DWR会自动跳过(skip)静态方法。表11-2列出了当creator属性采用不同的选择值时,其对应param子元素的param和value的值及其含义。
表11-2 creator元素选择值及其含义
creator值 |
param值 |
value值 |
new |
class |
|
scripted |
language |
|
scripted |
script |
返回供远程调用的对象的脚本 |
spring |
location* |
|
spring |
beanName |
为了安全考虑,将所有的Java类无选择地暴露给客户端Javascript是不理智的,所以必须加以控制和选择。create元素的include,exclude两个子元素用来对暴露给客户端Javascript的方法进行筛选,auth则能够将方法访问权限授予相应的角色对象(需要用到J2EE安全机制等)。注意,本节的示例第五步用到了一个src属性为“/ajaxlab/dwr/interface/ JDate.js”的Javascript文件。这个文件是DWR动态生成的。DWR根据dwr.xml的配置,将相应的Java类方法和属性转化为Javascript供客户端调用。所以在用户看来,就好像Javascript在调用本地对象一样。这些调用通过XMLHttpRequest对象转化为对uk.ltd.getahead.dwr.DWRServlet的请求,继而请求服务器响应。
create元素的creator属性负责公开用于Web远程的类和类的方法,convert元素的convertor属性则负责这些方法的参数和返回类型。convert元素的作用是告诉DWR在服务器端Java对象表示和序列化的Javascript之间如何转换数据类型。DWR自动地在Java和Javascript表示之间调整简单数据类型。这些类型包括Java原生类型和它们各自的类表示,还有String、Date、数组和集合类型。DWR也能把JavaBean转换成Javascript表示,但是为了安全考虑,做这件事要求显式的配置。
DWR应用中,所有的“/dwr/*”的请求都由这个DWRServlet来处理。当Web服务器启动的时候,DWRServlet调用init()方法完成初始化,设置日志级别、实例化DWRServlet用到的单例类、读取包括dwr.xml在内的配置文件。当“/dwr/*”请求送达的时候,DWRServlet的doGet,doPost方法调用processor.handle(req,res)方法,根据请求的URL完成如下事务。
请求URL为“/dwr/”根请求:将请求转向“/dwr/index.html”;
请求URL为“/dwr/index.html”:列出当前客户端可远程调用的全部Java类,页面仅供调试的时候使用;
请求URL为“/dwr/text/*”:为单独的Java类创建测试页面,页面仅供调试的时候使用;
请求URL为“/dwr/engine.js”或者“/dwr/uril.js”或者“/dwr/deprecated.js”:从dwr.jar包中读取相应Javascript文件的文件流,显示在页面上;
请求URL为“/dwr/interface/*”:将在dwr.xml中定义的Java类及其方法转化为Javascript函数;
请求URL为“/dwr/exec/”:处理远程Javascript请求;
请求URL为其他:设置http请求状态码为404,返回错误信息为“Page not found. In debug/test mode try viewing /[WEB-APP]/dwr/”。
既定的Java类已经通过DWR转化成可供客户端使用Javascript调用的方法和对象了。接下来就是使用Javascript调用这些暴露的方法和对象了。DWR最大的挑战在于如何将Java同步调用执行的特性与Ajax的异步特性结合起来。
DWR采用了XMLHttpRequest对象的回调机制来解决上述矛盾,即当响应数据从服务器返回是调用用户指定的回调函数。DWR提供两种方式为Javascript指定回调函数,即将回调函数名称加入参数列表,或者在参数列表中增加一个包含数据对象的调用。
将回调函数名称加入参数列表是最简单最常用的方式,本节的案例就使用了这种方式。假设Java类Remote提供的方法签名如下:
public class Remote() {
public String getData(int data) {……}
<script language="javascript" src="{webapp}/dwr/interface/Remote.js" > </script>
<script language="javascript" src="{webapp}/dwr/engine.js"></script>
function handleData(str) {window.alert(str);} //创建回调函数
Remote.getData(100,handleData); //调用Javascript,100是Remote类方法getData本身的参数。
这种方法有时候具有比较好的可读性,也可以添加额外的调用,还可以为回调函数定时并设置错误处理函数:
Remote.getData(100,{
callback:function(str){window.alert(str);},
timeout:5000,
errorHandler:function(message){window.alert("No options:"+messag
e);}
});
11.1.3 试用DWR
上一节的介绍中,Java自带类java.util.Date被用来示范如何将服务器端Java类暴露给浏览器端Javascript远程调用。这一节将使用自定义的类来展示DWR框架的具体应用。
接下来的例子采用了基于网上商店的模型,包含一个基本的产品表示类Item和一个数据存储查询访问对象CatalogDAO类。Item是一个普通的Java类,包含id,name,description,price四个属性及相应的geter,setter方法;CatalogDAO则包含getItem,findItems两个方法,getItem方法通过输入id参数取得特定的Item,findItems则以List形式返回当前全部的Item。在实际案例中,CatalogDAO的getItem和findItems方法所取得的数据一般来自持久化介质,如数据库。这里仅为示范及测试所需,所以返回硬编码,其大致代码如例程11-4所示。
例程11-4 Item
package com.ajaxlab.ajax;
public class Item {
private String id = "";
private String name = "";
private String description = "";
private int price = 0;
public Item() {
}
public Item(String id) {
this.id = id;
public String getId() {
return id;
public void setId(String id) {
public String getName() {
return name;
public void setName(String name) {
this.name = name;
public String getDescription() {
return description;
public void setDescription(String description) {
this.description = description;
public int getPrice() {
return price;
public void setPrice(int price) {
this.price = price;
public String getFormattedPrice() {
return "$"+String.valueOf(price);
例程11-5 CatalogDAO
import java.util.List;
import java.util.ArrayList;
public class CatalogDAO {
public CatalogDAO() {
public Item getItem(String id) {
Item item = new Item("产品-"+id);
item.setName("新品-"+id);
item.setPrice(100);
item.setDescription("中国制造.");
return item;
public List findItems(String expression) {
List list = new ArrayList();
Item item1 = new Item("产品-001");
item1.setName("新品-001");
item1.setDescription(expression);
item1.setPrice(10);
Item item2 = new Item("产品-002");
item2.setName("新品-002");
item2.setDescription(expression);
item2.setPrice(15);
Item item3 = new Item("产品-003");
item3.setName("新品-003");
item3.setDescription(expression);
item3.setPrice(35);
list.add(item1);
list.add(item2);
list.add(item3);
return list;
由于要将Item和CatalogDAO暴露给浏览器端Javascript远程调用,所以Item和CatalogDAO都提供了无参数的构造方法。这个例子将演示两个简单的用例:一是在文本框中输入产品ID,搜索对应的产品;二是单击“浏览产品”按钮,返回当前全部库存产品。
接下来设置DWR部署描述文件dwr.xml。create元素部分将CatalogDAO类的getItem,findItems方法暴露出来,convert元素则将Item类转化为普通的Javascript对象。DWR自动在Java和Javascript表示之间调整简单数据类型。这些类型包括Java基本类型及其各自的类表示,比如int和Integer,以及String、Date、数组和集合类型。在Item类中,为了显示格式化后的产品价格,增加了getFormattedPrice方法。dwr.xml的代码如例程11-6所示。
例程11-6 dwr.xml
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<create creator="new" javascript="CatalogDAO">
<param name="class" value="com.ajaxlab.ajax.CatalogDAO"/>
<include method="getItem"/>
<include method="findItems"/>
<convert converter="bean" match="com.ajaxlab.ajax.Item">
<param name="include" value="id,name,description,formatted- Price" />
</convert>
确保Web应用程序下的web.xml已经按照12.4.3节第二步添加了相应的Servlet映射,将dwr.xml拷贝到{APPLICATION_WEB_HOME}/WEB-INF目录下。启动Tomcat,打开浏览器,导航到http://localhost:8080/ajaxlab/dwr/index.html就能够看到CatalogDAO暴露出来的方法了,如图11-5和图11-6所示。
图11-5 暴露给Javascript的Java类
图11-6 CatalogDAO供Javascript远程调用的方法
在getItem,findItems两个方法后面的文本框的双引号中输入任何字符,单击“Execute”按钮。服务器返回的数据以弹出对话框的形式显示出来。getItem返回一个Javascript对象,findItems则返回一个数组直接量,如图11-7和图11-8所示。
Java类方法已经按照预定设想暴露给Javascript了,按照DWR的设计思想,在Web页面中,可以使用CatalogDAO.methodName(parameter1,parameter2…,callback)的方式调用CatalogDAO的方法。其中,callback是回调函数的名称。DWR并未严格的检查是否传送parameter参数给CatalogDAO方法。
图11-7 CatalogDAO返回的Javascript对象 图11-8 CatalogDAO返回的数组直接量
本例的Web页面包含两个文本框和两个按钮。文本框分别用来输入产品编号和产品描述,两个普通按钮则用来根据输入显示单个产品细节和全部产品列表。页面中还包括两个事件响应函数和两个回调函数,分别用来响应按钮单击事件和处理响应数据。
事件响应函数doSearch将输入框item_id的值连同回调函数showItem的名称作为参数传递给CatalogDAO.getItem方法。而事件响应函数doList则将输入框item_description的值连同回调函数showList的名称作为参数传递给CatalogDAO.findItems方法。
在回调函数showItem和showList中,使用到了名为$()的Javascript函数。这个函数是在DWR的util.js定义的,其功能与“document.getElementById()”相当。util.js中还定义了大量方便开发人员操作的便捷函数,具体可以参考util.js源码。sample12_2.jsp的Javascript部分代码如下所示,相应的运行效果如图11-9所示。
图11-9 使用DWR实现产品搜索
例程11-7 sample12_2.jsp
function doSearch() {
var item_id = document.form1.item_id.value;
if(item_id!="") CatalogDAO.getItem(item_id,showItem);
else document.getElementById("item_detail").innerHTML = "请输入产品编号。";
function showItem(data) {
var element = $("item_detail");
var str = "";
str = "<table width='600' cellspacing='0' cellpadding='4' border= '1'>";
str = str + "<caption>产品信息</caption>";
str = str + "<thead><td width='100'>编号</td><td width='100'>名称</td><td width='100'>价格</td><td width='300'>描述</td></thead>/r/n";
str = str + "<tbody><td width='100'>"+data.id+"</td><td width= '100'>"+data.name+"</td><td width='100'>"+data.formattedPrice+"</td><td width='300'>"+data.description+"</td></tbody>/r/n";
str = str + "</table>";
element.innerHTML = str;
function doList() {
CatalogDAO.findItems("中国制造。",showList);
function showList(data) {
var root = $("item_list");
var str = "<table width='600' cellspacing='0' cellpadding='4' border='1'>";
str = str + "<caption>全部产品</caption>";
str = str + "<thead><td width='100'>编号</td><td width='200'>名称</td><td width='100'>价格</td><td width='200'>描述</td></thead>/r/n";
str = str + "<tbody>/r/n";
for(var i=0;i<data.length;i++) {
str = str + "<thead><td width='100'>"+data[i].id+"</td><td width='200'>"+data[i].name+"</td><td width='100'>"+data[i].formattedPrice+"</td><td width='200'>"+data[i].description+"</td></thead>/r/n";
str = str + "</tbody></table>";
root.innerHTML = str;
11.1.4 DWR的适用范围
通过以上的介绍和试用可以看到DWR提供了许多东西,它允许迅速而简单地创建到服务器端Java对象的Ajax接口,而无须编写任何Servlet代码、对象序列化代码或客户端XMLHttpRequest代码。使用DWR部署到Web应用程序极为简单,而且DWR的安全特性可以与J2EE基于角色的验证系统集成。与手工编写Ajax应用程序相比,DWR通过Java映射机制、Java类对象与Javascript对象转换等方式,将服务器端Java类属性及其方法有选择地暴露给浏览器客户端,并应用一系列的扩展函数简化了Ajax应用程序开发,减少了开发量,提高开发效率。
但是,同任何RPC一样,对远程对象的每一个调用都要比本地函数调用来得昂贵,所以应该尽可能减少对远程对象的调用次数。与某些Java类、方法设计方式相比,DWR远程调用返回的数据应该尽量保持粗粒度,以防止多次频繁的调用远程对象。DWR在封装和隐藏Ajax机械性方面做的很好,但是这在一定程度上降低了Ajax的自由度。
实际上,使用DWR框架的Ajax应用将是一个高耦合的应用,因为DWR在客户端和服务器端代码之间形成了紧密的耦合。具体表现在:远程方法API的变化必须在DWR存根调用的Javascript上反映出来,必要时也必须修改dwr.xml部署描述文件,这点明显与当前广受推崇的MVC模式相悖。而这种考核会将客户端的调用考虑渗入到服务器端类方法等代码编写。典型的是,由于转换器的局限,某些Java方法和属性不能顺利转化为Javascript,所以常常有必要为这些方法特别添加额外的处理方法。所以,基于方便转换及其他的考虑,JavaBean的设计不再那么单纯和简单。同样,DWR的数据传输是采用异步方式,不要期望多个调用按照分派的顺序依次返回。
综上所述,如果读者希望能够将服务器端Java对象暴露给浏览器端Javascript,快速地创建Ajax应用程序,而且目标应用程序并不追求视图与控制器、模型层之间的低耦合,那么就可以考虑采用DWR来实现Ajax应用。由于篇幅的关系,本书并未涉及到DWR的全部特性。读者如果想深入学习DWR或者了解更多的内容,惟一的方式就是从其官方网站下载最新的文档和开发包,自己动手实践。
11.2.1 Ajax Tags简介
Ajax Tags是位于sourceforge.net上面的一个开源Ajax项目,其出发点在于应用标签封装的思想,实现一些常用的Ajax应用,提高开发效率。Ajax Tags提供一系列的标签,简化在JSP页面中使用Ajax的过程。Javascript在Ajax中占很大的比重,但实际上不少服务器端的开发人员掌握的Javascript知识并不完整(按照正常分工,页面构建应该是网页设计人员或者前端开发人员的职责)。Ajax Tags提供的标签能够让开发人员将JSP页面与Ajax应用快速的集成整合。
基于文本框的输入自动完成(autocomplete based on character input to an input field),类似Google Suggestion的搜索建议功能。
下拉列表级联选择(select Box population based on selections made from another field),即当选择一个下拉列表时,另一个下拉列表的列表项则根据上一个下拉列表的情况自动更新。
文本高显提示(callout or balloon popups for highlighting content),即当单击某个链接的时候,在其周围弹出文本框,显示相关提示信息。
图像关联(toggling images)。
表单域状态开启和关闭(form field states on/off)。
Ajax Tags的实现包含Javascript和Java类,其中,Java类基于JDK1.4编译,需要Servlet容器支持,而Javascript文件可以在Firefox1.1+和IE5.0以上版本环境下运行。
在编写本书的时候,Ajax Tags发布了其1.1版本。从Ajax Tags的官方网站http://ajaxtags.sourceforge.net/可以下载全部可用版本及相关文档。特别要注意的是,从其官方网站下载到的demo包,需要JSP2.0和Servlet2.4支持,Tomcat5.5可以满足要求。
像所有的Java标签库一样,Ajax Tags安装需要经历几个必要的步骤。下面的7步内容示范如何将Ajax Tags加入到2.4节创建的Java Web应用程序中。
第一步:确认运行环境,下载运行包。
Ajax Tags运行需要JDK1.4,以及支持Servlet2.3和JSP1.0的Web服务器,客户端需要Fireword1.1+或者IE5.0以上版本的浏览器。
从Ajax Tags的官方网站下载最新版本的运行包。本文使用其1.1.5版本,它是一个名为ajaxtags-1.1.5.zip的压缩包。读者也可以在本书的随书光盘software目录中找到。
下载Prototype framework,版本为1.3.1,下载地址为http://prototype.conio.net/。它是一个Javascript运行框架,用来简化动态Web的编程开发。
如果读者已经按照本书2.4节的要求创建了开发目录和工程,并下载了Ajax Tags运行包,则可以跳过这一步。
第二步:复制jar运行包及TLD文件。
复制下载后的jar运行包在{APPLICATION_WEB_HOME}/WEB-INF/lib目录下。这里采用1.1.5版本,故运行包名称为ajaxtags-1.1.5.jar。开发包内包含Ajax Tags运行所需的API及TLD等文件。
复制TLD文件ajaxtags.tld到{APPLICATION_WEB_HOME}/WEB-INF目录下。
由于Ajax Tags所使用的标签必须经过org.apache.taglibs包的解析,所以必须确保Tomcat的ClassLoad路径中有standard-1.0.6.jar或者其他包含org.apache.taglibs包的jar文件。
第三步:定义TLD映射。
对于JSP1.x的用户,修改web.xml部署描述文件,将下面这段代码添加到web.xml文件的标签库部分。
<taglib>
<taglib-uri> http://ajaxtags.org/tags/ajax </taglib-uri>
<taglib-location>/WEB-INF/ajaxtags.tld</taglib-location>
</taglib>
第四步:创建服务器端处理程序。
创建必要的服务器端响应处理程序,用来接受并处理浏览器发出的Ajax请求。这些处理程序可以是Java Servlet,JSP,Struts Action或者其他不是Java的服务器端组件。惟一的要求是,这些处理程序必须根据Ajax请求返回XML文档格式的结果列表,如例程11-8所示。
例程11-8 Ajax返回的XML文档格式
<?xml version="1.0" encoding="UTF-8"?>
<ajax-response>
<response>
<item>
<name>Record 1</name>
<value>1</value>
</item>
<name>Record 2</name>
<value>2</value>
<name>Record 3</name>
<value>3</value>
</response>
</ajax-response>
第五步:在JSP中定义TLD映射。
在每个需要使用Ajax Tags的JSP文件头部,添加如下的TLD映射:
<%@ taglib uri="http://ajaxtags.org/tags/ajax" prefix="ajax" %>
Ajax Tags封装了必要的Javascript操作,部分支撑函数由Prototype framework提供。将prototype-1.3.1.js和ajaxtags-1.1.5.js两个js文件复制到{APPLICATION_WEB_HOME}目录下,同时将以下两行代码加入到JSP文件的<head>标签部分,注意,src的属性值必须与存放两个js文件的路径对应。
<script type="text/javascript" src="prototype-1.3.1.js"></script>
<script type="text/javascript" src="ajaxtags-1.1.5.js"></script>
第七步:定义CSS样式。
部分Ajax Tags标签需要CSS样式支持才能展现良好的效果,比如,ajax:autocomplete标签就使用了无序列表(UL,LI)样式来显示一个下拉的列表。Ajax Tags建议开发人员定义必要的CSS样式表,之前下载的ajaxtags-1.1.5.zip中包含了一个供示范的CSS样式表文件。
对于第四步需要生成的XML文档,Ajax Tags提供了一个名为org.ajaxtags.helpers. Ajax XmlBuilder的帮助类来协助开发人员生成形式良好的XML文档,并将这份文档返回给浏览器,而这个过程只须传入一个列表(List)或者集合(Collection)对象。以返回一个类似第四步的XML文档为例,这个文档表示一个轿车品牌和型号,name值代表品牌,value值代表相应的型号。CarService类的getModelsByName()方法接受一个代表品牌的字符串,返回相应的型号列表。其代码段如下,modelName将输出为XML文档的name元素值,modelType将输出为对应的value值。
CarService service = new CarService();
List list = service.getModelsByName(modelName);
return new AjaxXmlBuilder().addItems(list,"modelName","modelType");
也可以调用AjaxXmlBuilder类的addItem()方法来单独添加列表:
AjaxXmlBuilder builder = new AjaxXmlBuilder();
for (Iterator iter = list.iterator(); iter.hasNext();) {
Car car = (Car) iter.next();
builder.addItem(car.getModelName(),car.getModelType());
return builder.toString();
由于AjaxXmlBuilder输出XML文档时需要用到org.apache.common.beanutils包,所以要确保ClassLoad路径中能够找到commons-beanutils.jar,commons-lang-2.1.jar。
Ajax Tags还提供了两个供参考的Ajax请求处理程序类,这两个类是针对Java Servlet和Struts Action。org.ajaxtags.servlets.BaseAjaxServlet类是一个抽象类,其他处理类只要继承这个类并实现getXmlContent(HttpServletRequest,HttpServletResponse)方法。org.ajaxtags. servlets.BaseAjaxAction类与org.ajaxtags.servlets.BaseAjaxServlet类似,只是它是基于Struts Action构建的。
11.2.2 Ajax Tags标签及其使用方法
目前,Ajax Tags标签包括ajax:auchors,ajax:area,ajax:autocomplete,ajax:callout,ajax:displayTag,ajax:htmlContent,ajax:portlet,ajax:select,ajax:tabPane,ajax:toggle。先来看看这些标签的共同属性及其含义。
1.Ajax Tags标签的共同属性及其含义
baseUrl。
baseUrl是每个Ajax Tags都用到的属性,用来指定标签所发出的http请求的目标处理程序的URL地址。例外的是,对于ajax:ajaxPanel标签,baseUrl只是其子标签ajax:tab的一个属性。baseUrl属性值所指向的目标处理程序必须返回XML文档格式的结果列表。
parameters。
parameters也是每个Ajax Tags都用到的属性,用来为该标签发起的http请求添加请求参数和值,这些参数和值将发送到baseUrl属性所指定的URL地址。这些参数和值以成对的形式出现,多个参数和值之间用逗号隔开。对于每对参数和值,可以指定参数值来自表单的某个域,这种情况的参数值用大括号{}包裹起来,大括号内是其对应的表单域ID,实际值则在事件被触发的时候取得。比如:
Parameters="modelName={modelId},modelType=A7VM"
postFunctions。
在某些情况下,需要将两个Ajax Tags标签关联起来,比如,后一个标签的值根据前一个标签的情况而改变,这就是postFunction所要做的事情。这个属性的值是一个Javascript函数的名称。当前一个标签的触发事件已经处理完毕,这个Javascript函数随即就会被调用。
errorFunction和emptyFunction。
Ajax Tags支持异常和空对象处理机制。当标签的errorFunction属性被指定的时候,如果Ajax发出的请求不能正常执行,则errorFunction属性值所对应的Javascript函数将被调用。当标签的emptyFunction属性被指定的时候,如果Ajax发出的请求返回内容为空,则emptyFunction属性值所对应的Javascript函数将被调用。
接下来看看Ajax Tags所定义的各个标签的含义及其属性值。
2.ajax:auchors标签
这个标签能够将HTML的<a>链接标记包裹的全部内容转换成Ajax链接,向服务器发起异步http请求。实际上,原来的<a>链接已经被onClick事件所取代,强制http请求通过Ajax发起。服务器所返回的http请求响应内容将显示面内任何已经定义的地方,其用法如例程11-9所示。
例程11-9 使用ajax:authors标签
<ajax:anchors target="ajaxFrame" ajaxFlag="ajaxFrame">
<!-- Ajax this link -->
Refresh first area <a href="${contextPath}/pagearea.jsp" class= "conten tLink"> </a>
</ajax:anchors>
<div id="ajaxFrame"></div>
ajax:auchors标签包含target和ajaxFlag两个属性。其中,target属性指定http请求响应数据将显示的页面区域,通常是一个DIV浮动层的ID。ajaxFlag属性代表一个布尔值(true/false),用来指定页面的其余部分是否应该被Ajax调用忽略,默认值为false。
3.ajax:area标签
ajax:area标签包裹的内容中,全部的<a>等链接将被重写。这些链接请求返回响应数据的时候,页面的某一部分会被更新,而不是刷新整个页面,其用法如例程11-10所示。
例程11-10 使用ajax:area标签
<ajax:area id="ajaxFrame"
style="width:300px; min-height:100px; height:100px;"
styleClass="textArea"
ajaxAnchors="true" ajaxFlag="ajaxFrame">
This is the first area and should be refreshed only when the first link or
the link inside itself is clicked:
It may include a link to <a href="${contextPath}/pagearea.jsp"> itse lf </a>
</ajax:area>
属 性 |
含 义 |
是否必需 |
id |
是 |
|
ajaxFlag |
否 |
|
style |
否 |
|
styleClass |
否 |
|
ajaxAuchors |
是否将区域内的<a>等链接全部转化成onClick事件 |
否 |
ajax:auchors和ajax:area标签的应用效果如11-10所示,当单击“itself”链接的时候,Date字符串所代表的字符串修改为当前日期。
图11-10 ajax:auchors和ajax:area标签的应用效果
4.ajax:autocomplete标签
ajax:autocomplete标签允许从服务器端Servlet提取一个值列表,以下拉列表的显示在HTML文本框下方,用户可以从中选择一项作为文本框输入值,即类似Google Suggestion的搜索建议功能。另外,这个标签还允许第二个区域的值用下拉列表项的值填充。其用法如例程11-11所示。
例程11-11 使用ajax:autocomplete标签
<form>
Make: <input id="model" name="model" type="text" size="30" class=" form- autocomplete" />
Model: <input id="make" name="make" type="text" size="30" />
</form>
<ajax:autocomplete
baseUrl="${pageContext.request.contextPath}/GetModel.view"
source="make"
target="model"
parameters="model={model}"
className="form-autocomplete"
progressStyle="throbbing"
minimumCharacters="1" />
ajax:autocomplete标签常用的属性及其含义如表11-4所示。
表11-4 auto:complete标签常用的属性及其含义
是否必需 |
||
baseUrl |
是 |
|
source |
是 |
|
target |
是 |
|
parameter |
用逗号分隔的传递给服务器Servlet/Action的参数列表 |
是 |
className |
是 |
|
progressStyle |
定义在输入文本框显示icon标志的样式表 |
否 |
forceSelection |
|
否 |
minimumCharacters |
在autocomplete执行前限制所需最小字符数 |
否 |
appendValue |
指定是把从下拉列表项的值加入文本框中还是简单的替换,布尔值类型,默认为false |
否 |
appendSeparator |
当appendValue选择把从下拉列表项的值加入文本框中时,指定文本框原值和加入值之间的分隔符。如果appendValue属性值为false,则此属性无效 |
否 |
ajax:autocomplete标签的应用效果如图11-11和11-12所示,当在文本框Name中输入字母R的时候,会弹出下拉列表。从该列表中任意选择一项,该项所对应的值即可填充到文本框Name和Make中。
图11-11 初始化后的ajax:autocomplete标签效果
图11-12 ajax:autocomplete标签的使用效果
11.2.2 Ajax Tags标签及其使用方法
2.ajax:auchors标签
3.ajax:area标签
4.ajax:autocomplete标签
图11-12 ajax:autocomplete标签的使用效果
9.ajax:select标签
ajax:select标签允许从后台Servlet或者Action取得一个值列表,填充到另外一个下拉列表框中,形成下拉列表级联选择,其用法如例程11-16所示。
例程11-16 使用ajax:select标签
Make:
<select id="make" name="make">
<option value="">Select make</option>
<c:forEach items="${makes}" var="make">
<option value="${make}">${make}</option>
</c:forEach>
</select>
Model:
<select id="model" name="model">
<option value="">Select model</option>
<ajax:select
baseUrl="${pageContext.request.contextPath}/GetCarModel.view"
parameters="make={make}"
postFunction="doOtherThings" />
需要注意的是,ajax:select标签必须包含在HTML的form标记内部。ajax:select标签常用的属性及其含义如表11-9所示。
是否必需 |
||
baseUrl |
指定处理请求的服务器端Servlet或者Action的URL |
是 |
source |
形成Ajax搜索请求的初始下拉列表框的ID |
是 |
target |
Ajax请求返回数据将填充的目标下拉列表框的ID |
是 |
parameters |
用逗号分隔的传递给服务器Servlet/Action的参数列表 |
是 |
eventType |
指定目标元素触发ajax行为填充页面的事件类型 |
否 |
ajax:select标签的应用效果如图11-17和图11-18所示。当选择Make下拉列表框的项时,其顶部的图片被修改,其下方的Model下拉列表框的数据会被更新。
10.ajax:tabPanel标签
ajax:tabPanel允许创建多个面板页,各个面板页的内容来源不同。ajax:tabPanel标签允许包含一个或者多个ajax:tab子标签,其用法如例程11-17所示。
例程11-17 使用ajax:tabPanel标签
<ajax:tabPanel
panelStyleId="tabPanel"
contentStyleId="tabContent"
currentStyleId="ajaxCurrentTab">
<ajax:tab caption="Ford"
baseUrl="${pageContext.request.contextPath}/htmlcontent. view?make=ford"
defaultTab="true"/>
<ajax:tab caption="Honda"
baseUrl="${pageContext.request.contextPath}/htmlcontent.view"
parameters="make=honda"/>
<ajax:tab caption="Mazda"
parameters="make=mazda"/>
</ajax:tabPanel>
ajax:tabPanel标签主要包含panelStyleId,contentStyleId,currentStyleId三个属性,分别用来控制面板、面板内容、活动面板的显示样式。ajax:tab标签则主要包含baseUrl,caption,defaultTab,parameters四个属性,其中baseUrl指定处理请求的服务器端Servlet或者Action的URL;caption属性指定面板的caption提示信息;defaultTab为布尔值,指定当前面板为默认面板;parameters则为用逗号分隔的传递给服务器Servlet/Action的参数列表。
ajax:tabPanel标签的应用效果如图11-19所示,其效果类似桌面应用程序的选项卡。这个效果需要定义必要的样式表。
11.ajax:toggle标签
ajax:toggle允许修改表单隐藏域的值为true或者false,或者通过改变图片的来源替换图片,或者改变HTML标记innerHTML值,如DIV,其用法如例程11-18所示。
例程11-18 使用ajax:toggle标签
<img id="watched" src="images/watched_false.gif" />
<div id="watchedResponseContainer">Status is currently:
<span id="watchedResponse">off</span>
</div>
<input type="hidden" id="watchedStatus" />
<script type="text/javascript">
function populateResponseContent(xml) {
var root = xml.documentElement;
var respNode = root.getElementsByTagName("response")[0];
var content = getValueForNode(respNode,"toggleContent");
$('watchedResponse').innerHTML = content;
}
</script>
<ajax:toggle
baseUrl="${pageContext.request.contextPath}/ToggleSwitch.view"
image="watched"
stateId="watchedStatus"
stateXmlName="toggleState"
imagePattern="${pageContext.request.contextPath}/img/watched_ {0}.gif"
postFunction="populateResponseContent" />
需要注意的是,ajax:toggle标签必须包含在HTML的form标记内部。此标签常用的属性及其含义如表11-10所示。
是否必需 |
||
baseUrl |
指定处理请求的服务器端Servlet或者Action的URL |
是 |
image |
是 |
|
state |
用于保存当前状态的表单隐藏域的ID |
是 |
stateXmlName |
是 |
|
imagePattern |
供替换的图片的URL地址 |
是 |
parameters |
用逗号分隔的传递给服务器Servlet/Action的参数列表 |
否 |
eventType |
指定目标元素触发toggle行为的事件类型 |
否 |
ajax:toggle标签的应用效果如图11-20所示。当单击“Toggle Me”左边的五角星图像时,其下方的DIV标签内容会被更改。
12.ajax:updateField标签
ajax:updateField标签允许根据一个表单域的值修改另外一个或者多个表单域的值,其用法如例程11-19所示。
例程11-19 使用ajax:updateField标签
<fieldset>
<legend>Velocity Conversion</legend>
<label for="mph">Miles/Hour (mph)</label>
<input type="text" id="mph" />
<input id="action" type="button" value="Go"/>
<label for="kph">Kilometers/Hour (kph)</label>
<input type="text" id="kph" />
<label for="mps">Meters/Second (m/s)</label>
<input type="text" id="mps" />
</fieldset>
<ajax:updateField
baseUrl="${pageContext.request.contextPath}/ConvertMPH.view"
source="mph"
target="kph,mps"
action="action"
parameters="mph={mph}" />
ajax:updateField标签常用的属性及其含义如表11-11所示。
表11-11 ajax:updateField标签常用的属性及其含义
属 性 |
含 义 |
是否必需 |
baseUrl |
指定处理请求的服务器端Servlet或者Action的URL |
是 |
source |
指定持有将传递给服务器的参数值的表单域的ID |
是 |
续表
是否必需 |
||
target |
是 |
|
action |
指定将触发更新事件的图片或者按钮的ID |
是 |
parameters |
用逗号分隔的传递给服务器Servlet/Action的参数列表 |
是 |
eventType |
指定目标元素触发toggle行为的事件类型 |
|
ajax:updateField标签的应用效果如图11-21所示。在“Miles/Hour(mph)”文本框中输入一个整数值,单击“Calculate”按钮,Miles/Hour数值将被计算,结果在其下方的两个文本框中显示。
图11-21 ajax:updateField标签的应用效果
13.表单域关联
在Ajax Tags中,多个表单域可以通过标签关联起来,形成依赖关系。最常用的方式是使用单个或者多个ajax:select标签。比如,在接下来的例子中,用户需要先后选择制造商、型号、生产年月,其表单域的HTML代码如例程11-20所示。其中,make下拉列表框使用JSTL的c:forEach标签来完成option值的循环迭代。
例程11-20 表单域关联的HTML代码
<select id="model" name="model" disabled="true">
Year:
<select id="year" name="year" disabled="true">
这个例子并未设置model和year两个下拉列表框的option初始值,它是通过用户选择make下拉列表框后由Ajax Tags标签来获取并填充。所以,需要使用两个ajax:select标签,第一个ajax:select标签将make和model两个下拉列表框关联起来,第二个ajax:select标签将model和year两个下拉列表框关联起来,其代码如例程11-21所示。
例程11-21 使用ajax:select标签实现表单域关联
fieldId="make"
targetId="model"
paramName="make"
postFunc="doOtherThings"/>
fieldId="model"
targetId="year"
baseUrl="${pageContext.request.contextPath}/GetCarYear.view"
paramName="model"
因此,当选择下拉列表框make的时候,服务器返回的数据被用来填充下拉列表框model;当选择下拉列表框model的时候,服务器返回的数据则被用来填充下拉列表框year。这种方式很容易构成多级级联的下拉列表框。
DWR是一个框架,简单的说就是能够在javascript直接调用java方法,而不必去写一大堆的javascript代码。它的实现是基于ajax的,可以实现无刷新效果。
网上有不少DWR的例子,但大都只是某种方法的调用,本文只在使用层面上介绍DWR,并不涉更多的技术与设计,其目的是让初学者能够很快的学会各种java方法在javascript中是如何调用的。
本文以DWR 1.1 为基础,对于DWR 2.0,因为还没有正式发布版,故不做介绍。
一、 dwr配置篇之web.xml
1 、最小配置
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
2、当我们想看DWR自动生成的测试页(Using debug/test mode)时,可在servlet配置中加上
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
这个参数DWR默认是false。如果选择true,我们可以通过 http://localhost:port/app/dwr看到你部署的每个DWR class。并且可以测试java代码的每个方法是否运行正常。为了安全考虑,在正式环境下你一定把这个参数设为false。
3、多个dwr.xml文件的配置
可能有几种情况,我们一一列举。一个servlet,多个dwr.xml配置文件;多个servlet,每个servlet对应一个或多个dwr.xml配置文件。
3.1、一个servlet,多个dwr.xml配置文件
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>config-1</param-name>
<param-value>WEB-INF/dwr1.xml</param-value>
</init-param>
<init-param>
<param-name>config-2</param-name>
<param-value>WEB-INF/dwr2.xml</param-value>
</init-param>
</servlet>
在这种配置下,param-name的值必须以config开头。param-name可以有>=0个。如果没有param-name,那么将会读取 WEB-INF/dwr.xml。如果有大于零个param-name,那么WEB-INF/dwr.xml文件将不会被读取。
3.2 、多个 servlet ,每个 servlet 对应一个或多个 dwr.xml
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>dwr-invoker1</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>config-admin</param-name>
<param-value>WEB-INF/dwr1.xml</param-value>
</init-param>
<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>
<servlet-mapping>
<servlet-name>dwr-invoker1</servlet-name>
<url-pattern>/dwr1/*</url-pattern>
</servlet-mapping>
在这种情况下,我们可以根据J2EE security来控制权限,针对不同url,加不同的角色。
二、 dwr使用篇
1.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod1"/>
</create>
</allow>
</dwr>
<allow>标签中包括可以暴露给 javascript 访问的东西。
<create>标签中指定 javascript 中可以访问的 java 类,并定义 DWR 应当如何获得要进行远程的类的实例。 creator="new" 属性指定 java 类实例的生成方式, new 意味着 DWR 应当调用类的默认构造函数来获得实例,其他的还有 spring 方式,通过与 IOC 容器 Spring 进行集成来获得实例等等。 javascript=" testClass " 属性指定 javascript代码访问对象时使用的名称。
<param>标签指定要公开给 javascript 的 java 类名。
<include>标签指定要公开给 javascript 的方法。不指定的话就公开所有方法。
1.2、javascript中调用
首先,引入 javascript 脚本
<script src='dwr/interface/ testClass.js'></script>
<script src='dwr/engine.js'></script>
<script src='dwr/util.js'></script>
其中 TestClass.js 是 dwr 根据配置文件自动生成的, engine.js 和 util.js 是 dwr 自带的脚本文件。
其次,编写调用 java 方法的 javascript 函数
Function callTestMethod1(){
testClass.testMethod1();
}
2.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod2"/>
</create>
</allow>
</dwr>
2.2、javascript中调用
首先,引入 javascript 脚本
其次,编写调用 java 方法的 javascript 函数和接收返回值的回调函数
Function callTestMethod2(){
testClass.testMethod2(callBackFortestMethod2);
}
Function callBackFortestMethod2(data){
//其中 date 接收方法的返回值
//可以在这里对返回值进行处理和显示等等
alert("the return value is " + data);
}
其中 callBackFortestMethod2 是接收返回值的回调函数
3.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod3"/>
</create>
</allow>
</dwr>
3.2、javascript中调用
首先,引入 javascript 脚本
其次,编写调用 java 方法的 javascript 函数
Function callTestMethod3(){
//定义要传到 java 方法中的参数
var data;
//构造参数
data = “test String”;
testClass.testMethod3(data);
}
4.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod4"/>
</create>
<convert converter="bean" match=""com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
<creator>标签负责公开用于 Web 远程的类和类的方法, <convertor> 标签则负责这些方法的参数和返回类型。 convert 元素的作用是告诉 DWR 在服务器端 Java 对象表示和序列化的 JavaScript 之间如何转换数据类型。 DWR 自动地在 Java 和 JavaScript 表示之间调整简单数据类型。这些类型包括 Java 原生类型和它们各自的封装类表示,还有 String 、 Date 、数组和集合类型。 DWR 也能把 JavaBean 转换成 JavaScript 表示,但是出于安全性的原因,要求显式的配置, <convertor> 标签就是完成此功能的。 converter="bean" 属性指定转换的方式采用 JavaBean 命名规范, match=""com.dwr.TestBean" 属性指定要转换的 javabean 名称, <param> 标签指定要转换的 JavaBean 属性。
4.2、javascript中调用
首先,引入 javascript 脚本
其次,编写调用 java 方法的 javascript 函数和接收返回值的回调函数
Function callTestMethod4(){
testClass.testMethod4(callBackFortestMethod4);
}
Function callBackFortestMethod4(data){
//其中 date 接收方法的返回值
//对于 JavaBean 返回值,有两种方式处理
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
alert(data.username);
alert(data.password);
}
其中 callBackFortestMethod4 是接收返回值的回调函数
5.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod5"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
5.2、javascript中调用
首先,引入 javascript 脚本
其次,编写调用 java 方法的 javascript 函数
Function callTestMethod5(){
//定义要传到 java 方法中的参数
var data;
//构造参数, date 实际上是一个 object
data = { username:"user",password:"password" }
testClass.testMethod5(data);
}
6.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod6"/>
</create>
<convert converter="bean" match="com.dwr.TestBean ">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
注意:如果 List 、 Set 或者 Map 中的元素均为简单类型(包括其封装类)或 String 、 Date 、数组和集合类型,则不需要<convert>标签。
6.2、javascript中调用(以返回List为例,List的元素为TestBean)
首先,引入 javascript 脚本
其次,编写调用 java 方法的 javascript 函数和接收返回值的回调函数
Function callTestMethod6(){
testClass.testMethod6(callBackFortestMethod6);
}
Function callBackFortestMethod6(data){
//其中 date 接收方法的返回值
//对于 JavaBean 返回值,有两种方式处理
for(var i=0;i<data.length;i++){
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
}
for(var i=0;i<data.length;i++){
alert(data.username);
alert(data.password);
}
}
7.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod7"/>
</create>
<convert converter="bean" match="com.dwr.TestBean ">
<param name="include" value="username,password" />
</convert>
</allow>
<signatures>
<![CDATA[
import java.util.List;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(List<TestBean>);
]]>
</signatures>
</dwr>
<signatures>标签是用来声明 java 方法中 List 、 Set 或者 Map 参数所包含的确切类,以便 java 代码作出判断。
7.2、javascript中调用(以返回List为例,List的元素为TestBean)
首先,引入 javascript 脚本
其次,编写调用 java 方法的 javascript 函数
Function callTestMethod7(){
//定义要传到 java 方法中的参数
var data;
//构造参数, date 实际上是一个 object 数组,即数组的每个元素均为 object
data = [
{
username:"user1",
password:"password2"
},
{
username:"user2",
password:" password2"
}
];
testClass.testMethod7(data);
}
注意:
1、对于第 6 种情况,如果 java 方法的返回值为 Map ,则在接收该返回值的 javascript 回调函数中如下处理:
function callBackFortestMethod(data){
//其中date接收方法的返回值
for(var property in data){
var bean = data[property];
alert(bean.username);
alert(bean.password);
}
}
2、对于第 7 种情况,如果 java 的方法的参数为 Map (假设其 key 为 String , value 为 TestBean ),则在调用该方法的 javascript 函数中用如下方法构造要传递的参数:
function callTestMethod (){
//定义要传到java方法中的参数
var data;
//构造参数,date实际上是一个object,其属性名为Map的key,属性值为Map的value
data = {
"key1":{
username:"user1",
password:"password2"
},
"key2":{
username:"user2",
password:" password2"
}
};
testClass.testMethod(data);
}
并且在dwr.xml中增加如下的配置段
<signatures>
<![CDATA[
import java.util.List;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(Map<String,TestBean>);
]]>
</signatures>
3、由以上可以发现,对于 java 方法的返回值为 List(Set) 的情况, DWR 将其转化为 Object 数组,传递个 javascript ;对于 java 方法的返回值为 Map 的情况, DWR 将其转化为一个 Object ,其中 Object 的属性为原 Map 的 key 值,属性值为原 Map 相应的 value 值。
4、如果 java 方法的参数为 List(Set) 和 Map 的情况, javascript 中也要根据 3 种所说,构造相应的 javascript 数据来传递到 java 中。