dwr学习文档

更新时间:2024-05-25 17:59:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

DWR: Easy AJAX for JAVA

DWR简介

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文件中。那部分需要和其他的在一起,部分也一样。

dwr-invoker DWR Servlet

uk.ltd.getahead.dwr.DWRServlet

debug true

dwr-invoker /dwr/*

在WEB-INF目录下的web.xml旁边创建一个dwr.xml文件。可以从最简单的配置开始:

\ \>

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

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

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

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

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

怎么在你的web应用中使用 在文档中有很多例子演示如何动态更改页面中的文字、更新列表、操作表单,还有直接更改table中的内容。每一个都有如何实现的介绍。 另一种方式是看刚才的页面中提供的代码:

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

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

你也可以把其中/[YOUR-WEBAPP]/替换成你的web页面的相对路径。 译者注:如果是JSP最好用request.getContextPath()

如何写与DWR交互的Javascript代码。

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

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

DWR通过引入回调函数来解决这个问题,当结果被返回时,DWR会调用这个函数。 有两种推荐的方式来使用DWR实现远程方法调用。可以通过把回调函数放在参数列表里,也可以把回调函数放到元数据对象里。

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

假设你有一个这样的Java方法: public class Remote {

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

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

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(\ + 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:\ age:42,

appointments:[ new Date(), new Date(\};

Remote.setPerson(p);

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

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

传递额外的数据到callback函数

通常我们需要传递额外的数据到callback函数,但是因为所有的回调函数都只有一个参数(远程方法的返回结果),这就需要一些小技巧了。 解决方案就是使用Javascript的闭包特性。 例如,你的回调函数原本需要像这个样子:

function callbackFunc(dataFromServer, dataFromBrowser) { // 用dataFromServer和dataFromBrowser做些事情...... }

那么你可以像这个组织你的函数:

var dataFromBrowser = ...;

// 定义一个闭包函数来存储dataFromBrowser的引用,并调用dataFromServer var callbackProxy = function(dataFromServer) { callbackFunc(dataFromServer, dataFromBrowser); };

var callMetaData = { callback:callbackProxy };

Remote.method(params, callMetaData); (调用元数据在脚本介绍中有解释)

换句话说,现在你作为callback函数传递过来的不是一个真正的callback,他只是一个做为代理的闭包,用来传递客户端的数据。 你可以用更简介的形式:

var dataFromBrowser = ...; Remote.method(params, {

callback:function(dataFromServer) {

callbackFunc(dataFromServer, dataFromBrowser); }

});

使用DWR的一些技巧

这里有些东西可以帮你使用DWR。如果你也有什么使用技巧,也添加进来吧。

创建一个\组件

我不建议你做自己的suggest组件。让一些基础的东西工作起来是很容易的,但是让键盘导航正常的工作却不那么容易。有一些库里面已经包含的suggest组件:

Script.aculo.us 里有一个 Autocompleter.Local 函数,可以和DWR整合起来。让Local版的组件和DWR的远程调用结合起来要比直接让Remote版的组件工作起来更容易一些,因为Remote版的组件一般对服务器上的工作又特殊要求。你会可以在DWR的用户邮件列表中找到相关的信息,也可以看Rubens的blog

另外,Rimu Hosting的Peter实现了一个自己的Suggest组件,也是可以和DWR一起用的,查看这里 增强文件上传

Pierre Losson写了一个如何把DWR和Commons-Fileupload组件结合起来的文章。很不错,并且源码和演示都有。 改进加载信息

DWR 1.0 中的useLoadingMessage()函数有点问题,你可以自己定义这一信息,但是要小心调用。你也可以把这个函数中的问题修正一下。更多信息可以参看useLoadingMessage()的文档。 使用Server控制台

DWR可以报告出详细的错误信息,这些信息可以帮你找出你的程序错在哪里。如果你的程序出现什么异常,你应该仔细查看你的web容器开始或运行过程中出现的错误信息。一般错误信息会在WARNING或ERROR级别,但是INFO级别的信息也很有用。

如果你的log信息中又什么错误,但是你想知道的更详细的信息,可以查看INFO级别的信息,因为有时错误信息和后台信息会被一起输出到log里。 使用debug/test页面

debug/test页面对于查找错误也很有用。查看 http://localhost:8080/[YOUR-WEBAPP ]/

开始指南中有基本使用方法。但是一定要记住在发现错误时可以在这些页面找到有用的信息。

访问HttpServletRequest 详细参见这里 向回调函数传递参数

通常我们需要把额外的信息传递给callback函数,但是所有的callback函数只有一个参数(远程方法的返回码),这就需要一些技巧了。这里有一整篇文章阐述这个问题。 服务器性能优化

CPU瓶颈:经过严格的测试DWR的性能没什么问题。DWR上性能消耗同web服务器和网络比起来可以忽略不计。如果你真的需要提升DWR的性能的话,可以把log级别设置ERROR或FATAL,但是主要还是要看你的编码情况。

Network瓶颈: DWR没有管理你的浏览器缓存的功能,所以它会不断的重复读取DWR的javascript文件。这里有一个简单的解决办法,把javascript文件复制到你的web-app中,这样web服务器就可以更好的利用它了。你也可以考虑把所有的javascript文件合并成一个文件,然后用DOJO的压缩程序处理一个来节省流量。

我们可以做一个补丁,让DWR在web-app启动的时候用时间做为javascript文件的时间戳,但是这个并不十分重要,因为上面的补丁太简单了而且可以压缩合并Javascript文件。

WEB-INF/web.xml 参考手册

在web.xml中最简单的配置就是简单加入DWR的servlet,没有这个配置DWR就不会起作用:

dwr-invoker

uk.ltd.getahead.dwr.DWRServlet

dwr-invoker /dwr/*

此外还可以加入一些重要和有用的参数。

Logging

DWR可以工作在JDK1.3上,而JDK1.3不支持java.util.logging,但是我们想强迫任何人使用commons-logging或者log4j,所以当没有logging类的时候DWR就使用HttpServlet.log()方法。尽管如此,如果DWR发现了commons-logging,就是使用它。 Commons-Logging

几乎每一个人都在使用commons-logging,因为大多数的servlet容器在使用它。所以如果你的web应用中没有明显的加入commons-logging包,它也会默认的配置好。 在这种情况下,logging是由java.util.logging或者log4j配置文件控制的。详细配置查看文档。

HttpServlet.log()

如果你用HttpServlet.log(), 下面的配置控制logging:

logLevel DEBUG

可用的值有:FATAL, ERROR, WARN (默认), INFO 和 DEBUG。

多个dwr.xml文件 和 J2EE安全

一般来说,你只需要一个dwr.xml文件,并且放置在默认的位置:WEB-INF/dwr.xml。 如果那样的话,你可以不用了解下面的配置。 有三个原因使你希望指定不同位置的dwr.xml文件。

?

你希望让dwr.xml文件和它能访问到的资源在一起。在这种情况下你需要一个这样的配置:

WEB-INF/classes/com/yourco/dwr/dwr.xml

你有大量的远程调用类,希望把他们分成多个文件。在这种情况下你需要重复下面的配置几次,每一个中有不同的 param-name,并且以 'config' 开头。DWR会依次把他们都读进来。

DWR可以使用Servlet规范的J2EE的URL安全机制来给不同的用户不同的访问权限。你只需要简单的定义多个dwr servlet,并且制定不同的名字,url和访问权限。

?

?

如果你希望使用这一功能,那么语法是这样的:

config***** WEB-INF/dwr.xml

What config file do we use?

在这里config*****意思是param-name要以字符串'config'开头。这个参数可以根据需要使用多次,但是不能相同。 一个使用J2EE的安全机制的例子:

dwr-user-invoker

uk.ltd.getahead.dwr.DWRServlet

config-user

WEB-INF/dwr-user.xml

dwr-admin-invoker

uk.ltd.getahead.dwr.DWRServlet

config-admin

WEB-INF/dwr-admin.xml

dwr-admin-invoker /dwradmin/*

dwr-user-invoker /dwruser/*

dwr-admin

dwr-admin-collection /dwradmin/*

admin

dwr-user

dwr-user-collection /dwruser/*

user

使用插件(Plug-in)

DWR里的很多部件都是可插入的,所以所以可以通过替换掉DWR的默认实现类来改变其功能。你可以在 中的 param-name 中指定你要替换的接口,并在 param-value 中指定自己的接口实现类。 可插入点是:

? ? ? ? ? ?

uk.ltd.getahead.dwr.AccessControl uk.ltd.getahead.dwr.Configuration

uk.ltd.getahead.dwr.ConverterManager uk.ltd.getahead.dwr.CreatorManager uk.ltd.getahead.dwr.Processor

uk.ltd.getahead.dwr.ExecutionContext

这些可插入点默认的实现都在uk.ltd.getahead.dwr.impl中。

使用debug/test模式

你可以通过下面的参数让DWR进入debug/test模式:

debug true

在debug模式里,DWR会为每一个远程调用类生成一个测试页面。这对于检查DWR是否工作和工作的怎么样是很有用的。这个模式还可以警告你一些存在的问题:javascript保留字问题,或者函数重载问题。

尽管如此,这个模式不应该使用在实际部署环境里面,因为它可以为攻击者提供你的服务的大量信息。如果你的网站设计的好的话,这些信息不会帮助攻击者窥视你的网站内容,但是还是不要给任何人一个找到你错误的机会好。

DWR就是照上面的样子做的,没有任何保证,所以你的网站的安全是你的责任。请小心。 配置DWR - dwr.xml

dwr.xml是DWR的配置文件。默认情况下,应该把它放到WEB-INF目录(web.xml的目录)下。

创建dwr.xml文件 dwr.xml文件的结构如下:

\ \>

... 术语

这里是一些必须理解的术语 - 参数会被converted,远程Bean会被created。所以如果你有一个叫A的bean,它有一个方法叫A.blah(B) 那么你需要一个A的creator和一个B的converter。

allow段落里面定义的试DWR可以创建和转换的类。 Creators

我们要调用的每个类都需要一个定义。creator有几种。比较通用的是new关键字和Spring。

The Creators – 创造器

dwr.xml文件中的create元素的结构如下:

...

这里的多数元素都是可选的 - 你真正必须知道的是指定一个creator和一个javascript名字。

creator属性 是必须的 - 它用来指定使用那种创造器。

默认情况下DWR1.1有8种创造器。它们是:

?

new: 用Java的new关键字创造对象。

'new' 创造器

new创造器在DWR中已经默认声明了:

class=\ 。你不需要在dwr.xml文件中添加这段话,它已经存在于DWR的内部dwr.xml文件中了。 这个创造器通过类默认的够早函数创造对象实例。用new创造器有一些好处:

? ?

安全:DWR创造的对象生存的事件越短,多次调用中间的值不一致的错误机会越少。 内存消耗低: 如果你的站点用户量非常大,这个创造器可以减少VM的内存溢出。

你可以通过下面的方式使用new创造器来创造远程调用Bean:

...

这些代码把 java.util.Date 映射成Javascript,并且命名为Blah,所以在Javascript

中当你调用Blah.toString(reply) 那么一个新的 java.util.Date 就会通过默认的构造函数创造出来, 然后 toString() 方法被调用, 然后结果数据返回给reply方法(在这个例子中date是字符串格式)。

? ? ?

none: 它不创建对象,看下面的原因。 (v1.1+)

scripted: 通过BSF使用脚本语言创建对象,例如BeanShell或Groovy。 spring: 通过Spring框架访问Bean。

让DWR和Spring一起工作的步骤

1. 确认你用的是最新版的DWR。Spring创造器已经有了变化,所以你最好检查一下

DWR的最新版本。

2. 确认你查看过开始指南中的内容。

3. 确认你的Spring的Bean在DWR外面运行良好。 4. 配置DWR和Spring一起工作。 (看下面)

5. 查看演示页面: http://localhost:8080/[ YOUR-WEBAPP ]/dwr ,检查spring

的Bean是否出现。

DWR对于Spring没有运行期依赖,所以如果你不使用Spring那么Spring的支持不会产生任何影响到。

The SpringCreator

这个创造器会查找spring的中配置的Bean,用Spring去创建它们。如果你已经在使用Spring,那么这个创造器会非常有用。

你可以通过下面的方式来创建远程调用的Bean: ...

寻找你的Spring配置

有三种方式寻找配置文件: ContextLoaderListener

最简单的方式是使用org.springframework.web.context.ContextLoaderListener。你不必使用所有的Spring-MVC功能,只需要这个Listener就够了,所以这是个不错的方案。你需要在WEB-INF/web.xml中做如下配置:

contextConfigLocation /WEB-INF/classes/beans.xml

org.springframework.web.context.ContextLoaderListener

我能找到的ContextLoaderListener的最好的文档就是javadoc。如果你知道还有更好的文档,请告知我。 Rob Sanheim 指出还有一个能深入了解ContextLoaderListener的文档。

使用location*参数

如果你要在dwr.xml中指定使用哪些bean,你可以使用location*参数。你可以指定任意多个文件,只要参数以location开始并且唯一即可。例如:location-1, location-2。这些location被用做Spring的ClassPathXmlApplicationContext的参数: ...

直接设置BeanFactory

SpringCreator有一个静态方法 setOverrideBeanFactory(BeanFactory) 用来通过编程的方式直接设置BeanFactory。 配置DWR和Spring

Bram Smeets写了一个有意思的blog,教你配置DWR使用beans.xml代替WEB-INF/web.xml。

我也对于如何在beans.xml中指定dwr.xml很感兴趣,尽管这看上去有些Spring传染病的感觉。有人知道如何实现吗?请加入邮件列表并告诉大家。

? ?

jsf: 使用JSF的Bean。 (v1.1+)

JSF 整合

DWR包括两个JSF的扩展点,一个创造器和一个ServletFilter。 'jsf'创造器

DWR1.1中有一个体验版的JsfCreator。你可以哉dwr.xml中这样使用: ...

...

这将允许你通过DWR调用ManagedBean。 The Servlet Filter

DWR/Faces 过滤器允许你不在JSF的生命周期里调用FacesContext中的Bean。 要使用JsfCreator,你应该把DWR/Faces过滤器加到web.xml中。

DwrFacesFilter

uk.ltd.getahead.dwr.servlet.FacesExtensionFilter

DwrFacesFilter /dwr/*

这两个需要放在web.xml中与其他的filter和filter-mapping放在一起。

? ?

struts: 使用Struts的FormBean。 (v1.1+)

整合Struts

DWR几乎可以和任何Framework一起工作。这个网站(DWR的官方网站)就是这一点的有力证明,因为它是在Drupal(PHP)中使用DWR。

DWR和Struts整合有两个层次。最基础的层次就是同时使用两个Framework,这是非常容易的,但是这样就不允许在DWR和Struts之间共享Action了。

DWR可以调用任何方法,所以没有理由不让你从DWR调用Struts的Action,除非你不想这样用。ActionForm的内容是什么,当返回ActionForward时DWR怎么做?

一个比较好方法是重构你想调用的Action,提取出Action的逻辑。DWR和你的Action就可以同时调用相同的方法了。 The 'struts' 创造器

DWR1.1增加了一个StrutsCreator。你可以哉dwr.xml中这样使用: ...

...

这样就允许你在DWR中调用FormBean了。

开始顺序

如果你要使用StrutsCreator那么你保证Struts在DWR之前被初始化。你可以在web.xml中把Struts的设置的比DWR低。

? ?

pageflow: 访问Beehive或Weblogic的PageFlow。 (v1.1+)

如果你需要写自己的创造器,你必须在init部分注册它。

javascript属性 用于指定浏览器中这个被创造出来的对象的名字。你不能使用Javascript的关键字。

scope属性 非常类似servlet规范中的scope。 它允许你指定这个bean在什么生命范围。选项有\和\。这些值对于Servlet和JSP开发者来说应该相当熟悉了。

scope属性是可选的。默认是\。如果要使用\需要cookies。当前的DWR不支持ULR重写。

param元素 被用来指定创造器的其他参数,每种构造器各有不同。例如,\创造器需要知道要创建的对象类型是什么。每一个创造器的参数在各自的文档中能找到。请查看上面的链接。

include和exclude元素 允许创造器来限制类中方法的访问。一个创造器必须指定include列表或exclude列表之一。如果是include列表则暗示默认的访问策略是\拒绝\;如果是exclude列表则暗示默认的访问策略是\允许\。

例如要拒绝防范除了setWibble()以外的所有方法,你应该把如下内容添加到dwr.xml中。

对于加入到create元素中的类的所有方法都是默认可见的。 auth元素 允许你指定一个J2EE的角色作为将来的访问控制检查: 'none' 创造器

'none' 创造器不创建任何对象 - 它会假设你不需要创建对象。这有可能是对的,有两个原因。

你可能在使用的scope不是\看上面),并在在前面已经把这个对象创建到这个scope中了,这时你就不需要再创建对象了。

还有一种情况是要调用的方法是静态的,这时也不需要创建对象。DWR会在调用创建器之前先检查一下这个方法是不是静态的。

对于上诉两种情况,你仍然需要class参数,用来告诉DWR它是在操作的对象类型是什么。 使用静态方法

DWR会在调用创建器之前先检查一下这个方法是不是静态的,如果是那么创造器不会被调用。很显然这个逻辑适用于所有创造器,尽管如此\创造器是最容易配置的。 适用单例类

对于单例类的创建,最好适用BeanShell和BSF来实例化对象。详细信息参见'Scripted'创造器 其他创造器

我么偶尔也需要一些新的创造器,最常见的是一个EjbCreator。讨论新的创造器的好地方是在邮件列表。

DWR和HttpSessionBindingListeners

DWR1.x中存贮已经创造的Bean的方法需要注意,它在每次请求时都会调用相同的 setAttribute() 方法。就是说,如果一个Bean在dwr.xml中的声明周期设置为session,再每次调用bean中的方法时,DWR都会执行一次 session.setAttribute(yourBean) 。这看上去没有什么危害,但是如果你要使用servlet的事件机制的,就是说用了HttpSessionBindingListener接口,你就会发现valueBound和valueUnbound事件在每次调用时都会发生,而不是你想像的在bean被创建时以及session过期时。 DWR2 只在第一次创建对象时调用 setAttribute() 。

Converters

我们必须保证所有的参数都可以被转换。JDK中的多数类型已经有转换器了,但是你需要给DWR转换你的代码的权利。一般来说JavaBean的参数需要一个定义。 默认情况下,如下类型不需要定义就可以转换:

? ? ? ? ? ? ?

所有的原生类型 boolean,int,double, 等等

原生类型的对象类型 Boolean,Integer,等等

java.lang.String

java.util.Date 和SQL中的Date 以上类型组成的数组

以上类型的集合类型 (Lists, Sets, Maps, Iterators, 等)

从DOM, XOM, JDOM 和 DOM4J中的DOM对象 (类似 Element 和 Document)

基础的转换器

原生类型,String,像BigDecimal这样的简单对象的转换器已经有了。你不需要在dwr.xml中部分的中定义。它们默认支持。

默认支持的类型包括: boolean, byte, short, int, long, float, double, char, java.lang.Boolean, java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, java.lang.Double, java.lang.Character, java.math.BigInteger, java.math.BigDecimal 和 java.lang.String

Date转换器

Date转换器负责在Javascript的Date类型与Java中的Date类型(java.util.Date, java.sql.Date, java.sql.Times or java.sql.Timestamp)之间进行转换。同基础的转换器一样,DateConverter默认是支持的。

如果你有一个Javascript的字符串 (例如\,你想把它转换成Java的Date类型有两个办法:在javascript中用Date.parse()把它解析成Date类型,然后用DWR的DateConverter传递给服务器;或者把它作为字符串传递给Server,再用Java中的SimpleDateFormat(或者类似的)来解析。

同样,如果你有个Java的Date类型并且希望在HTML使用它。你可以先用

SimpleDateFormat把它转换成字符串再使用。也可以直接传Date给Javascript,然后用Javascript格式化。第一种方式简单一些,尽管浪费了你的转换器,而且这样做也会是浏览器上的显示逻辑受到限制。其实后面的方法更好,也有一些工具可以帮你,例如:

? ?

The Javascript Toolbox Date formatter Web Developers Notes on Date formatting

其他对象

其实创建自己的转换器也很简单。Converter接口的Javadoc包含了信息。其实这种需要很少出现。在你写自己的Converter之前先看看BeanConverter,它有可能就是你要的。

数组转换器(Array Converter)

数组实体不太容易理解。默认情况下DWR能转换所有原生类型的数组,还有所有

marshallable对象的数组。这些marshallable对象包括前面介绍的String和Date类型。

高级Java程序员应该能够理解为什么match属性看上去很怪。

上面没有解释*的作用 - 它是通配符,表示匹配接下来的所有字符串。这也是DWR可以转换任意类型的数组的原因。

Bean 和 Object 转换器(Bean and Object Converters )

两个没有默认打开的转换器是Bean 和 Object 转换器。Bean转换器可以把POJO转换成Javascript的接合数组(类似与Java中的Map),或者反向转换。这个转换器默认情况下是没打开的,因为DWR要获得你的允许才能动你的代码。

Object转换器很相似,不同的是它直接应用于对象的成员,而不是通过getter和setter方法。下面的例子都是可以用object来替换bean的来直接访问对象成员。 如果你有一个在 中声明的远程调用Bean。它有个一参数也是一个bean,并且这个bean有一个setter存在一些安全隐患,那么攻击者就可能利用这一点。

你可以为某一个单独的类打开转换器:

如果要允许转换一个包或者子包下面的所有类,可以这样写: 显而易见,这样写是允许转换所有的JavaBean:

BeanConverter 和 JavaBeans 规范

用于被BeanConverter转换的Bean必须符合JavaBeans的规范,因为转换器用的是Introspection,而不是Reflection。这就是说属性要符合一下条件:有getter和setter,setter有一个参数,并且这个参数的类型是getter的返回类型。setter应该返回void,getter应该没有任何参数。setter没有重载。以上这些属于常识。如果你用的不是JavaBean,那么你应该用ObjectConverter.

设置Javascript变量

DWR可以把Javascript对象(又名maps,或联合数组)转换成JavaBean或者Java对象。

一个简单的例子可以帮助你。假设你有下面的Java代码: public class Remoted {

public void setPerson(Person p) { // ...

} }

public class Person {

public void setName(String name) { ... } public void setAge(int age) { ... } // ... }

如果这个Remoted已经被配置成Creator了,Persion类也定义了BeanConverter,那么你可以通过下面的方式调用Java代码: var p = { name:\Remoted.setPerson(p);

限制属性转换

就像你可以在creator的定义中剔出一些方法一样,converter也有类似的定义。 限制属性转换仅仅对于Bean有意义,很明显原生类型是不要需要这个功能的,所以只有BeanConverter及其子类型(HibernateBeanConverter))有这个功能。 语法是这样的:

这就保证了DWR不会调用 fred.getProperty1() 和fred.getProperty2两个方法。另外如果你喜欢\白名单\而不是\黑名单\的话:

安全上比较好的设计是使用\白名单\而不是\黑名单\。

对象的私有成员

通过'object'转换器的参数的一个名为force的参数,可以让DWR通过反射来访问对象私有成员。

语法是这样的:

直到DWR1.1.3,这里有一个bug,public的field反而不能被发现,所以你需要在public成员上设置force=true

集合类型转换器(Collection Converter )

有个两个默认的转换器,针对Map和Collection:

一般来说这些转换器可以递归转换它们的内容。 但是也有两点不足之处:

? ?

仅仅用反射机制是没有方法明确集合里面是什么类型的。所以这两个转换器不能把集合里面的东西转换成有意义的Javascript对象。 不能明确是那种类型的集合。

虽然我们不能让他们自动的起作用,我们可以在dwr.xml中用signatures语法声明它们类型,使之正确转换。

枚举类型转换器(Enum Converter)

枚举类型转换器默认是没有打开的。它在Java5中的Enum和Javascript的String之间进行转换。这个转换器默认关闭是因为DWR要在转换你的代码之前得到你的同意。 枚举类型转换器是DWR 1.1版以后才支持的。 你可以这样设置来打开这个转换器:

设置Javascript变量

一个简单的例子。假设你有下面的Java代码:

public class Remoted {

public void setStatus(Status p) { // ... } }

enum Status { PASS, FAIL, }

如果Remoted类已经配置好Creator,并且Status枚举类型已经设置了EnumConverter。那么你就可以在javascript中这样调用: Remoted.setStatus(\如果没有匹配的类型,就会抛出异常。

DOM 对象(DOM Objects )

DWR可以自动转换来之DOM,DOM4J,JDOM和XOM的DOM树。你可以简单得用上面这些类库返回一个Document、Element或者Node,DWR会把他们自动转换成浏览器的DOM对象。

在程序启动的时候会有一个常见的关于JDOM转换器的警告,你可以放心的忽略它,除非你要用JDOM:

INFO: Missing classdef for converter 'jdom'. Failed to load uk.ltd.getahead.dwr.convert.JDOMConverter. Cause: org/jdom/Document 因为DWR没有办法知道你是否想用JDOM,所以这个信息设在INFO级别的。

如果你曾经尝试过使用JDOM,你会意识到在这种情况下这个转换器不可用的 - 这也是我们显示这个信息的原因。 exist-db.org

我相信DWR能同exist-db很好的工作,因为它是建立在W3C DOM之上的,而DWR也支持这个。

DWR 和 Hibernate(Hibernate整合)

让DWR和Hibernate正常工作的检查列表

1. 确保你使用的是最新的DWR。Hibernate转换器是新东西,所以你需要下载最新

2. 确保你已经明白开始指南上所写的内容。

3. 确保你的Hiberante在没有DWR的时候工作正常。 4. 如果是Spring和Hibernate一起使用,那么你最好先了解一下如何将整合Spring。 5. 配置DWR,使之与Hibernate一起工作。 (看下面)。

6. 查看演示页面:http://localhost:8080/YOUR-WEBAPP/dwr,确定Spring的

Bean可以出现。 HibernateBeanConverter

这个转换器同标准的BeanConverter非常相似,不同之处在于我们可以决定如何处理延迟加载。

使用HibernateBeanConverter可能会带来如下风险:

? ?

架构: HibernateBeanConverter不符合MVC模式,所以不能把对象在数据曾和表现曾之间进行隔离。这个风险可以通过在上面加上独立的bean来减轻。

性能: DWR试图通过相同的序列化方式来转换所有可以得到的属性(除了DWR仅仅读JavaBean属性的时候)。所以可能会出现通过HTTP序列化了你的整个数据的情况。通常这并不是你想要的。要减少这一风险可以使用

BeanConverter(HibernateBeanConverter衍生于它)的排除某些属性的功能:

HibernateBeanConverter会尝试不去读取没有初始化的属性。如果你只是想读取所有的东西那么应该使用BeanConverter。

建议使用Hibernate3,实际上Hibernate2一下的情况,你会发现你得到的都是空的Bean。

Session管理

如果你使用Hibernate对象,你需要知道每一个DWR请求都是一个新的Servlet请求,所以你需要保证为每个请求打开一个Hiberante的Session。

如果你用Spring,那么可以很方便的使用Spring里面的OpenSessionInViewFilter,它可以保证为每个请求打开一个Hiberante的Session。类似的解决方案在其它Framework中也存在。

Servlet Objects (HttpServletRequest, HttpSession, etc)

可选的init部分用来声明创造bean的类和转换bean的类。多数情况下你不需要用到他们。如果你需要定义一个新的Creator [JavaDoc] 和 Converter [JavaDoc] , 那么你就需要在这里定义他们。但是建议你现检查一下DWR是不是已经支持了。

在init部分里有了定义只是告诉DWR这些扩展类的存在,给出了如何使用的信息。这时他们还没有被使用。这中方式很像Java中的import语句。多数类需要在使用前先import一下,但是只有import语句并不表明这个类已经被使用了。每一个creator和converter都用id属性,以便后面使用。

dwr.xml中的签名(Signatures)

DWR使用反射来找出在转换时应该用那种类型。有时类型信息并不明确,这时你可以在这里写下方法的签名来明确类型

signatures段使DWR能确定集合中存放的数据类型。例如下面的定义中我们无法知道list中存放的是什么类型。

public class Check {

public void setLotteryResults(List nos) { ... } }

signatures段允许我们暗示DWR应该用什么类型去处理。格式对以了解JDK5的泛型的人来说很容易理解。

import java.util.List; import com.example.Check;

Check.setLotteryResults(List nos); ]]>

DWR中又一个解析器专门来做这件事,所以即便你的环境时JDK1.3 DWR也能正常工作。

解析规则基本上会和你预想规则的一样(有两个例外),所以java.lang下面的类型会被默认import。

第一个是DWR1.0中解析器的bug,某些环境下不能返回正确类型。所以你也不用管它了。 第二个是这个解析器时\阳光(sunny day)\解析器。就是说它非常宽松,不想编译器那样严格的保证你一定正确。所以有时它也会允许你丢失import:

import java.util.List;

Check.setLotteryResults(List); ]]>

将来的DWR版本会使用一个更正式的解析器,这个编译器会基于官方Java定义,所以你最好不要使用太多这个不严格的东西。

signatures段只是用来确定泛型参数中的类型参数。DWR会自己使用反射机制或者运行时类型确定类型,或者假设它是一个String类型。所以: 不需要signatures - 没有泛型参数:

public void method(String p); public void method(String[] p); 需要signatures - DWR不能通过反射确定:

public void method(List p);

public void method(Map p); 不需要signatures - DWR能正确的猜出:

public void method(List p); public void method(Map p); 不需要signatures - DWR可以通过运行时类型确定:

public List method(String p);

没有必要让Javascript中的所有对象的key都是String类型 - 你可以使用其他类型作为key。但是他们在使用之前会被转换成String类型。DWR1.x用Javascript的特性把key转换成String。DWR2.0可能会用toString()方法,在服务段进行这一转换。

DWR Annotations

从DWR2.0(正在开发)开始,你也可以用Annotations来配置DWR DWR标注是用来代替dwr.xml或者与其一同工作的。 初始配置

要使用DWR的标注,你需要在web.xml中配置不同的DWR控制器。

DWR controller servlet DWR controller servlet

org.directwebremoting.servlet.DwrServlet

classes

com.example.RemoteFunctions, com.example.RemoteBean

servlet参数classes定义的时可以标注的类的全名,这些名字用逗号分割。 远程访问类

要使一个简单的class可以成为远程访问类,你需要使用@Create和@RemoteMethod标注。 @Create

public class RemoteFunctions { @RemoteMethod

public int calculateFoo() { return 42; } }

没有被@RemoteMethod标注的方法不能被远程访问。

要在Javascript使用不同于类型的名字,使用@Create标注的 name 属性。 @Create(name=\)

public class RemoteFunctions { } 对象转换

要使一个简单的bean类可以被远程访问, 使用@Convert和@RemoteProperty标注: @Convert

public class Foo { @RemoteProperty private int foo;

public int getFoo() { return foo; }

@RemoteProperty public int getBar() { return foo * 42; } }

要使用复杂的转换器,使用@Convert标注的 converter 属性。

engine.js: 处理所有与服务器的通信 engine.js Functions

engine.js对DWR非常重要,因为它是用来转换来至动态生成的接口的javascript函数调用的,所以只要用到DWR的地方就需要它。 The engine.js file

每一个页面都需要下面这些语句来引入主DWR引擎。

使用选项

下面这些选项可以通过 DWREngine.setX() 函数来设置全局属性。例如: DWREngine.setTimeout(1000);

或者在单次调用级别上(假设Remote被DWR暴露出来了): Remote.singleMethod(params, { callback:function(data) { ... }, timeout:2000 });

远程调用可以批量执行来减少反应时间。endBatch 函数中可以设置选项。 DWREngine.beginBatch();

Remote.methodInBatch1(params, callback1); Remote.methodInBatch2(params, callback2); DWREngine.endBatch({ timeout:3000 });

可以混合这几种方式,那样的话单次调用或者批量调用级别上的设置可以复写全局设置(就像你希望的那样)。当你在一个批量处理中多次设置了某个选项,DWR会保留最后一个。所以如果 Remote.singleMethod() 例子在batch里面,DWR会使用3000ms做为超时的时间。

callback和exceptionHandler两个选项只能在单次调用中使用,不能用于批量调用。 preHook和postHook选项两个选项是可添加的,就是说你可以为每一次调用添加多个hook。全局的preHook会在批量调用和单次调用之前被调用。同样全局的postHook会在单次调用和批量调用之后被调用。

如果以上叙述让你感到混乱,不用担心。DWR的的设计往往和你想象中的一样,所以其实这些并不复杂。 选项索引

下面是可用选项列表。 Option asyncGlobal Batch Call 1.1 1.1 1.1 Summary 设置是否为异步调用,不推荐同步调用 headers parameters 2.0 2.0 2.0 2.0 2.0 2.0 在XHR调用中加入额外的头信息 可以通过Meta-datarequest.getParameter()取得的元数据 选择GET或者POST. 1.x中叫'verb' 选择是使用xhr, iframe或者script-tag来实现远程调用. 1.x中叫'method' 某个调用是否应该设置为batch中的一部分或者直接的。这个选项和上面都有些不同。 *没有setSkipBatch()方法,批量调用是通过beginBatch()和endBatch()来控制的。 设定超时时长,单位ms httpMethod2.0 2.0 2.0 rpcType2.0 2.0 2.0 skipBatch1.0* 2.1? - timeout 1.0 1.1 1.1 处理器(Handler)

Option Global Batch Call Summary errorHandler1.0 1.1 当出了什么问题时的动作。1.x中还包括服务端的异常。从2.0开始服务端异常通过1.1 'exceptionHandler'处理 当因为浏览器的bug引起问题时的动作,所2.0 以默认这个设置为null(关闭) 2.0 当得到不正常的text/html页面时的动作(通常表示超时) warningHandler1.0 2.0 textHtmlHandler 2.0 2.0 调用处理器(Call Handler) (注册到单独调用上的,而不是batch中的所有调用)

Option callbackGlobal Batch Call - - 1.0 Summary 调用成功以后的要执行的回调函数,应该只有一个参数:远程调用得到的数据 远程调用失败的动作,一般是服务端异常或者数据转换问题。 exceptionHandler - - 2.0 Call Batching

你可以使用batch来批量的执行远程调用。这样可以减少与服务器的交互次数,所以可以提交反应速度。

一个batch以 DWREngine.beginBatch() 开始,并以 DWREngine.endBatch() 结束。当 DWREngine.endBatch() 被调用,我们就结束了远程调用的分组,这样DWR就在一次与服务器的交互中执行它们。

DWR会小心的处理保证所有的回调函数都会被调用,所以你可以明显的打开和关闭批处理。只要别忘了调用endBatch(),否则所有的远程调用永远的处于列队中。 警告

很明显,把一些远程调用放在一起执行也会产生一些影响。例如不能在batch里面执行同步调用。

所有的元数据选项,例如hooks, timeouts和errorHandlers都在batch级别的,而不是单次调用级别上的。所以如果一个batch中有两个调用设置了不同的超时,除了最后一个其他的都被忽略。

顺序调用

因为Ajax一般是异步调用,所以远程调用不会按照发送的顺序返回。

DWREngine.setOrdered(boolean) 允许结果严格按照发送的顺序返回。DWR在旧的请求安全返回以后才去发送新的请求。

我们一定需要保证请求按照发送的顺序返回吗?(默认为false)

警告 : 把这个设置为true会减慢你的应用程序,如果一个消息丢失,浏览器就会没有响应。很多时候即使用异步调用也有更好的解决办法,所以在用这一功能之前先好好考虑一下。

处理错误和警告

当因为一些原因调用失败,DWR就会调用错误和警告handler(根据错误的激烈程度),并传递错误消息。

你可以用这种方法来在alert窗口或状态来中显示错误信息。

你可以使用DWREngine.setErrorHandler(function)来改变错误处理方式,同样通过DWREngine.setWarningHandler(function)来改变警告处理方式。

更多关于处理错误和警告,请查看错误处理页面。 设置超时

DWREngine.setTimeout(),单次调用和批量调用级别的元数据选项,允许你设置一个超时值。全局的DWREngine.setTimeout()函数设置全局超时。如果设置值为0(默认)可以将超时关掉。

setTimeout()的单位是毫秒。如果调用超时发生,错误处理器就会被调用。 一个例子:

Remote.method(params, {

callback:function(data) { alert(\); }, errorHandler:function(message) { alert(\); }, timeout:1000 });

如果Remote.method()调用超过了1分钟还没有返回,\消息就会被显示。 Hooks (一个batch中可以注册多个hook)

Option Global Batch Call preHookSummary 1.0 1.1 1.1 1.1 远程调用前执行的函数 1.1 远程调用后执行的函数 postHook1.0 远程调用Hooks

DWREngine.setPreHook(function) 和 DWREngine.setPostHook(function) 。 如果你想在DWR调用之前出现一个提示,你可以设置pre-hook函数。它将会被调用,但是没有参数传递到这个函数。当你希望让一些按钮在调用期间变灰来防止被再次使用,这一功能将会很有用。

post-hook用来和pre-hook一起使用来逆转pre-hook产生的做的一些改变。 一个使用pre和post hook的例子就是 DWRUtil.useLoadingMessage() 函数。

全局选项(在单次调用或者批量调用中不可用)

Option orderedGlobal Batch Call 1.0 2.0 2.0 - - - - - - Summary DWR是否支持顺序调用 选择xhr或者iframe的反转Ajax 是否查找inbound调用 pollType reverseAjax 废弃的选项

Option Global Batch Call verb method 1.0 1.0 1.1 1.1 Summary 1.1 2.0废弃。使用'httpMethod'代替 1.1 2.0废弃。使用'rpcType'代替 将来的

Option onBackButton Global Batch Call 2.1? 2.1? 2.1? - - Summary 用户按了back按钮后的动作 用户按了forward按钮的动作 onForwardButton 2.1? 远程调用选项

DWR有一些选项用来控制远程调用的处理方式。method和verb对于用户应该时透明的,但是不同的浏览器效果的可能不一样。一般来说DWR会选择正确方法来处理,但是这些选项对于在不同效果的浏览器之间开发很有用。

DWREngine.setAsync(flag)

DWR1.0不支持。

我们指定让XHR异步调用了吗? 默认为true。警告如果你使用的时IFrame或者ScriptTag这一选项被忽略。一般来说把他变成false是个糟糕的做法。因为那样会使你的浏览器变慢。 要设置全局同步机制:

DWREngine.setAsync(true); 或者设置单次调用同步: Remote.method(params, {

callback:function(data) { ... }, async:true });

或者在batch里面: DWREngine.beginBatch();

Remote.method1(params, callback1); Remote.method2(params, callback2); DWREngine.endBatch({ async:true });

DWREngine.setMethod(newmethod)

用来设置恰当的方法。setMethod()不能把正使用你选择的方法,它只是保证首先尝试使用那个方法。newmethod必须是DWREngine.XMLHttpRequest或者DWREngine.IFrame,或者2.0以后的DWREngine.ScriptTag。

XMLHttpRequest时默认的,并且大多情况下可用。当ActiveX禁用IFrame就有用了,尽管DWR能自动检测出这种情况并切换到IFrame。当你要突破跨域调用的限制,ScriptTag就很有用了。

例如,要设置全局的远程调用方法:

DWREngine.setMethod(DWREngine.IFrame); 或者单次调用:

Remote.method(params, {

callback:function(data) { ... }, method:DWREngine.IFrame });

或者批量调用:

DWREngine.beginBatch();

Remote.method1(params, callback1);

Remote.method2(params, callback2); DWREngine.endBatch({ method:DWREngine.IFrame });

DWREngine.setVerb(verb)

这个选项允许你选择POST和GET,无论时用iframe还是XMLHttpRequest方法。一些浏览器(例如,旧版的Safari)不支持XHR-POST所以DWR就自动切换到GET,即使你设置POST为verb。所以setVerb()应当被仅仅做为一个堤示。 如果使用ScriptTag来远程调用,设置verb时没有的。 例如,设置全局远程调用的verb: DWREngine.setVerb(\); 设置单次调用:

Remote.method(params, {

callback:function(data) { ... }, verb:\ });

设置批量调用:

DWREngine.beginBatch();

Remote.method1(params, callback1); Remote.method2(params, callback2); DWREngine.endBatch({ verb:\ }); 保证的责任

DWR的目的是让你确切的知道所有调用的动作。知道了浏览器存在的bug,这是可以做到了。

如果你设置了callback, exceptionHandler, errorHandler, warningHandler 和 textHtmlHandler,DWR就应该 总是 为每一个请求提供响应。

util.js: 帮你使用从服务器取来的数据改变页面(还有一些灵巧的小功能)

util.js包含了一些工具函数来帮助你用javascript数据(例如从服务器返回的数据)来更新你的web页面。

你可以在DWR以外使用它,因为它不依赖于DWR的其他部分。你可以下载整个DWR或者单独下载.

4个基本的操作页面的函数:getValue[s]()和setValue[s]()可以操作大部分HTML元素除了table,list和image。getText()可以操作select list。

要修改table可以用addRows()和removeAllRows()。要修改列表(select列表和ul,ol列表)可以用addOptions()和removeAllOptions()。

还有一些其他功能不是DWRUtil的一部分。但它们也很有用,它们可以用来解决一些小问题,但是它们不是对于所有任都通用的。

$()

$() 函数(它是合法的Javascript名字) 是从Protoype偷来的主意。大略上的讲: $ = document.getElementById。 因为在Ajax程序中,你会需要写很多这样的语句,所以使用 $() 会更简洁。

通过指定的id来查找当前HTML文档中的元素,如果传递给它多个参数,它会返回找到的元素的数组。所有非String类型的参数会被原封不动的返回。这个函数的灵感来至于prototype库,但是它可以在更多的浏览器上运行。 可以看看DWRUtil.toDescriptiveString的演示。

从技术角度来讲他在IE5.0中是不能使用的,因为它使用了Array.push,尽管如此通常它只是用来同engine.js一起工作。如果你不想要engine.js并且在IE5.0中使用,那么你最好为Array.push找个替代品。

util.js: 生成列表(addOptions and removeAllOptions())

DWR的一个常遇到的任务就是根据选项填充选择列表。下面的例子就是根据输入填充列表。

下面将介绍 DWRUtil.addOptions() 的几种是用方法。

如果你希望在你更新了select以后,它仍然保持运来的选择,你要像下面这样做: var sel = DWRUtil.getValue(id); DWRUtil.removeAllOptions(id);

DWRUtil.addOptions(id, ...); DWRUtil.setValue(id, sel);

如果你想加入一个初始的\选项那么你可以直接加入下面的语句: DWRUtil.addOptions(id, \\[\]); 然后再下面紧接着加入你真正的选项数据。 DWRUtil.addOptions有5种模式

数组: DWRUtil.addOptions(selectid, array) 会创建一堆option,每个option的文字和值都是数组元素中的值。

对象数组 (指定text): DWRUtil.addOptions(selectid, data, prop) 用每个数组元素创造一个option,option的值和文字都是在prop中指定的对象的属性。

对象数组 (指定text和value值): DWRUtil.addOptions(selectid, array, valueprop, textprop) 用每个数组元素创造一个option,option的值是对象的valueprop属性,option的文字是对象的textprop属性。

对象: DWRUtil.addOptions(selectid, map, reverse)用每个属性创建一个option。对象属性名用来作为option的值,对象属性值用来作为属性的文字,这听上去有些不对。但是事实上却是正确的方式。如果reverse参数被设置为true,那么对象属性值用来作为选项的值。

对象的Map: DWRUtil.addOptions(selectid, map, valueprop, textprop) 用map中的每一个对象创建一个option。用对象的valueprop属性做为option的value,用对象的textprop属性做为option的文字。

ol 或 ul 列表: DWRUtil.addOptions(ulid, array) 用数组中的元素创建一堆li元素,他们的innerHTML是数组元素中的值。这种模式可以用来创建ul和ol列表。

util.js: 生成Table(addRows and removeAllRows )

DWR通过这两个函数来帮你操作table: DWRUtil.addRows() 和 DWRUtil.removeAllRows() 。这个函数的第一个参数都是table、tbody、thead、tfoot的id。一般来说最好使用tbody,因为这样可以保持你的header和footer行不变,并且可以防止Internet Explorer的bug。

DWRUtil.removeAllRows()

语法:

DWRUtil.removeAllRows(id);

本文来源:https://www.bwwdw.com/article/u8a7.html

Top