您的位置:首页 > 编程语言 > Java开发

DWR: Easy AJAX for JAVA 学习笔记

2008-12-26 10:18 696 查看
DWR是一个Java开源库,帮助你实现Ajax网站。

它可以让你在浏览器中的Javascript代码调用Web服务器上的Java,就像在Java代码就在浏览器中一样。

DWR主要包括两部分:

在服务器上运行的Servlet来处理请求并把结果返回浏览器。
运行在浏览器上的Javascript,可以发送请求,并动态改变页面。
DWR会根据你的Java类动态的生成Javascript代码。这些代码的魔力是让你感觉整个Ajax调用都是在浏览器上发生的,但事实上是服务器执行了这些代码,DWR负责数据的传递和转换。

这种Java和Javascript之间的远程调用会让DWR用户感觉像是曾经习惯使用的RMI或SOAP的RPC机制。而且这一过程还不需要额外的浏览器插件。

Java是同步的,而Ajax是异步的。所以当你调用一个远程方法时,你要给DWR一个回调函数,当数据从网络上回来时,DWR会调用这个函数。



这个图表现了DWR是如何在onclick事件中改变下拉列表的内容的。

DWR动态为服务端AjaxService类(Java)生成了一个相应的客户端AjaxService类(Javascript)。这个类被eventHandler调用。DWR就会去处理整个远程调用的细节,包括在Javascript和Java之间转换参数和返回值。然后在这里例子中,它会执行你提供的回调函数(populateList),这个函数再利用DWR提供的工具函数来更改页面内容。

DWR帮你生产出具有很好交互性的网站,它提供的一些Javascript库帮你处理DHTML,也提供了一些例子做为参考。

如何开始用DWR

有两种方法开始DWR,简单的方式是下载WAR文件然后看看。但是这不能帮你知道如何轻松的把DWR整合到你的web应用中,所以还是推荐你按照下面的3个步骤做:

1. 安装DWR的Jar包

下载dwr.jar文件

。把它放到你的webapp的WEB-INF/lib目录下。那里可能已经有很多其他的jar文件了。

2. 编辑配置文件

需要把下面的代码加到WEB-INF/web.xml文件中。<servlet>那部分需要和其他的<servlet>在一起,<servlet-mapping>部分也一样。

<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>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

在WEB-INF目录下的web.xml旁边创建一个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>
<create creator="new" javascript="Demo">
<param name="class" value="your.java.Bean"/>
</create>
</allow>
</dwr>

DWR配置文件定义了那些DWR会创建提供远程调用的Javascript类。在上面的例子中我们定义了两个类来提供远程调用,并为其提供的Javascript类的名字。

在上面我们使用了new创建器,它会调用没有参数的构造函数来创建实例,但是所有JavaBean必须有这一构造函数。还要注意DWR有一些限制:


不要出现Javascript保留关键字;和保留关键字同名的函数指定被排除。多数Javascript的关键字和Java是相同的。所以你不可能有一个方法叫做"try()"。但是该死"delete()"对与Javascript有着特殊意义,而对Java则不是。
Javascript方法重载是不支持的,所以尽量不要再Java中使用。

3. 访问下面的URL

http://localhost:8080/[YOUR-WEBAPP]/dwr/

你可以看见一个页面,里面有第二步中的类。接着往里点,你会看到所有可以调用的方法列表。这个页面是动态生成用来测试的例子。

自己动手试一下!

怎么在你的web应用中使用

在文档中有很多例子演示如何动态更改页面中的文字、更新列表、操作表单,还有直接更改table中的内容。每一个都有如何实现的介绍。

另一种方式是看刚才的页面中提供的代码:

http://localhost:8080//[YOUR-WEBAPP/]/dwr/ 页面,点击你的类。查看源码,找到执行方法的那几行,把那些文字粘贴到你的HTML或JSP中。

要包括下面这些能产生神奇效果的Javascript文件的链接。

<script src='/[YOUR-WEBAPP]/dwr/interface/[YOUR-SCRIPT].js'></script>
<script src='/[YOUR-WEBAPP]/dwr/engine.js'></script>

你也可以把其中/[YOUR-WEBAPP]/替换成你的web页面的相对路径。

译者注:如果是JSP最好用request.getContextPath()

写与DWR交互的javascript代码

DWR根据dwr.xml生成和Java代码类似的Javascript代码。

相对而言Java同步调用,创建与Java代码匹配的Ajax远程调用接口的最大挑战来至与实现Ajax的异步调用特性。

DWR通过引入回调函数来解决这个问题,当结果被返回时,DWR会调用这个函数。

有两种推荐的方式来使用DWR实现远程方法调用。可以通过把回调函数放在参数列表里,也可以把回调函数放到元数据对象里。

当然也可以把回调函数做为第一个参数,但是不建议使用这种方法。因为这种方法在处理自动处理http对象时(查看"Alternative Method")上会有问题。这个方法主要是为向下兼容而存在的。

简单的回调函数

假设你有一个这样的Java方法:

public class Remote {
public String getData(int index) { ... }
}

我们可以在Javascript中这样使用:

<script type="text/javascript"
src="[WEBAPP]/dwr/interface/Remote.js"> </script>
<script type="text/javascript"
src="[WEBAPP]/dwr/engine.js"> </script>
...

function handleGetData(str) {
alert(str);
}

Remote.getData(42, handleGetData);

42是Java方法getData()的一个参数。

此外你也可以使用这种减缩格式:

Remote.getData(42, function(str) { alert(str); });

调用元数据对象(Meta-Data)

另外一种语法时使用"调用元数据对象"来指定回调函数和其他的选项。上面的例子可以写成这样:

Remote.getData(42, {
callback:function(str) { alert(str); }
});

这种方法有很多优点:易于阅读,更重要的指定额外的调用选项。

超时和错误处理

在回调函数的元数据中你可以指定超时和错误的处理方式。例如:

Remote.getData(42, {
callback:function(str) { alert(str); },
timeout:5000,
errorHandler:function(message) { alert("Oops: " + message); }
});

查找回调函数

有些情况下我们很难区分各种回调选项(记住,Javascript是不支持函数重载的)。例如:

Remote.method({ timeout:3 }, { errorHandler:somefunc });

这两个参数之一是bean的参数,另一个是元数据对象,但是我们不能清楚的告诉DWR哪个是哪个。为了可以跨浏览器,我们假定null == undefined。 所以当前的情况,规则是:

如果第一个或最后一个是一个函数,那么它就是回调函数,没有元数据对象,并且其他参数都是Java的方法参数。
另外,如果最后一个参数是一个对象,这个对象中有一个callback成员,并且它是个函数,那么这个对象就是元数据对象,其他的都是Java方法参数。
另外,如果第一个参数是 null ,我们就假设没有回调函数,并且其他的都是Java方法参数。尽管如此,我们会检查最后一个参数是不是null,如果是就发出警告。
最后如果最后一个参数是null,那么就没有callback函数。
另外,发出错误信号是个糟糕的请求格式。

创造一个与Java对象匹配的Javascript对象

假设你有这样的Java方法:

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

Person对象的结构是这样的:

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

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

var p = {
name:"Fred Bloggs",
age:42,
appointments:[ new Date(), new Date("1 Jan 2008") ]
};
Remote.setPerson(p);

在Javascript没有出现的字段,在Java中就不会被设置。

因为setter都是返回'void',我们就不需要使用callback函数了。如果你想要一个返回void的服务端方法的完整版,你也可以加上callback函数。很明显DWR不会向它传递任何参数。

如果它不能工作怎么办?

TransformerFactoryConfigurationError

这个问题的现象是在启动有DWR的Web应用时出现如下stack trace:

root cause
javax.xml.transform.TransformerFactoryConfigurationError:
Provider org.apache.xalan.processor.TransformerFactoryImpl not found
javax.xml.transform.TransformerFactory.newInstance(Unknown Source)

这个问题和DWR没有什么关系,那是因为Tomcat没有配置好。比较简单的解决办法是下载Xalan替换掉$TOMCAT-HOME/common/lib目录下的xalan.jar文件。DWR2.0能更好的处理这个问题,但是本质的问题还是因为DWR的XML序列化需要有XSLT解析器的支持。

如果你用JDK5还是有这个问题的话,你可以增加以下VM参数来使Tomcat正常工作。

-Djavax.xml.transform.TransformerFactory=
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl

XML解析错误

在刚开始用DWR的时候经常遇到的一个错误就是XML解析错误。其实这和DWR没有多大关系,主要是因为Tomcat里面自带的Xerces的问题,要不是该有的时候没有,要不是不该有的时候有了。

JDK 1.3自身没有XML解析器,所以你需要xercesImpl.jar和xml-apis.jar.
JDK 1.4.0 和 JDK 1.4.1 虽然有了XML解析器,但是有很多bug,所以你还是需要把xercesImpl.jar放到tomcat/common/endorsed目录下。
JDK 1.4.2和JDK 5自带的XML解析器工作的很好,你就不需要再加其他的了。
另外要提的一点是,不同版本的Tomcat需要的XML解析器不一样。所以要注意检查它和JDK的版本兼容性。

用BEA Weblogic的Classpath问题

Weblogic 8.1(有可能其他版本同样)可能找不到DWR的类。

这大多出现在dwr.jar放在APP-INF目录下(APP_INF/lib)的情况。在这种情况下DWR依然可以工作,例如debug页面可以看见,但是DWR找不到你的类。

解决办法是把dwr.jar放到WEB-INF/lib目录下。

没有cookies的情况下用DWR

当不能用cookies时,servlet规范通过URL重写来支持HttpSession。DWR 2.x通过它生成的URL来支持这项功能。但是DWR 1.x没有这个功能。你可以通过以下办法让DWR 1.x 也支持cookies:

从dwr.jar中提取engine.js,保存到你的文件系统中,就像jsp文件一样.
修改"DWREngine._sendData = function(batch)" 方法, 加入一行:

statsInfo += ";jsessionid=" + <%="'"+session.getId()+"'"%>


这样就可以让DWR 1.x支持url重写了。DWR 2+默认支持。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: