一
Ajax--
整合的力量
2005
年,伴随着
Web2.0
的东风,
Ajax
逐渐进入国内开发人员的视线,并风靡全国。这个在
2005
年
2
月份由
Adaptive Path
公司的
Jesse James Garrett
命名的综合技术,综合利用
Javascript
、
XHTML
和
CSS
、
DOM
、
XMLHttpRequest
(以下称之为
XHR
)、
XML
和
XSTL
等技术,为
Web
应用程序提供异步的
http
请求处理方式,帮助
Web
应用程序实现类似桌面应用程序的快速反应功能并提供更加优秀的用户体验效果。
从
Ajax
身上,可以很清晰的看到各种技术整合到一起之后所表现出来的非凡魅力:
ü
其使用
XHTML
和
CSS
实现标准化的呈现界面。
ü
其使用
DOM
实现动态的显示和交互。
ü
其使用
XHR
实现与服务器的异步通信。
ü
其使用
Javascript
将
XHTML
、
DOM
、
XML
、
XHR
绑定。
不过要熟练使用
Ajax
进行开发,必须对
Javascript
、
XHR
相当熟悉,这对于不少程序员来说确实是个挑战。随着
Ajax
应用和研究的深入,各式各样的开源框架、包、程序库纷纷涌现。这些程序包和框架分别从各自的角度入手,试图降低
Ajax
开发的难度,比如减少
Javascript
脚本的开发量,加快开发的速度。
就目前而言,开源
Ajax
程序包和框架主要从以下几个方面对
Ajax
进行封装和扩展:
ü
远程调用工具包
远程调用工具包是
Ajax
框架最底层的工具包,其通常使用自己的
API
封装
XHR
对象,使得调用
XHR
更加简单直观。在
XHR
之前,我们通常使用内嵌的
IFRAME
来实现无刷新页面发送
http
请求的效果。因此,这些远程调用包必须支持那些不支持
XHR
的浏览器,以提高兼容性。
类似的工具包比如
Dojo
、
Prototype
等,他们都是纯
Javascript
的,适用于任何的服务端程序语言。
DWR
、
Ajax.NET
、
JSON-RP
等则是基于代理的
Ajax
框架,其允许
Javascript
直接与后台服务器端的类实现映射,是客户端的
Javascript
可以通过他们直接访问服务器对象。
ü
UI
工具包和组件
基于底层的远程调用工具包,可以很容易的实现一些胖客户端所需要的常用功能、组件和效果,比如目录树、标签面板以及菜单。这些都是可复用的。典型的比如
Script.aculo.us
,其在
Prototype
的基础上,创建了大量不同类型的
UI
效果,比如
Opacity
(不透明性)、
Movement
(移动)、
Highlight
(高显)等等。
ü
Web
应用程序工具包
这些工具包的目的在于模仿操作系统典型的
UI
效果,以创造与桌面应用程序更加接近的用户体验。典型的比如
SmartClient
,其所提供的组件能模拟
Windows
或者
Mac OSX
的
UI
效果。
ü
基于自定义标签的工具包
这些工具包利用
JSP
支持自定义标签的特点,通过自定义标签封装
Ajax
应用,使传统的
HTML
控件在必要的时候具备
Ajax
功能,比如以异步方式处理表单的提交和响应,打开超链接内容的时候不重新加载页面等等。通过这些工具包,我们能够将复杂的功能封装在
HTML
风格的特定标签中,使用
Java
代码自动处理格式化、访问外部资源等
HTML
和
Javascript
所无法处理的任务。典型的比如
Ajax Tags
。
ü
Ajax
化的
Web
框架
当前主流的
Web
框架都意识到
Ajax
的价值所在,纷纷提供对
Ajax
的支持。逐渐的,我们也可以根据自己所使用的
Web
框架,从开源项目中寻找符合要求的
Web
框架扩展。比如,
Struts Ajax Tags
就提供对
Struts
标签的扩展。
ü
代码动态生成
在
Ruby on Rails
社区,
Ruby helper
功能能够自动生成基于
Prototype
的
Javascript
代码;而
Webwork2
,则利用
Dojo
工具包,在
Java
平台上实现同样的功能。
ü
基于组件
在
.NET
领域,已经有
Ajax.NET
、
Atlas
等可复用的
Ajax
组件,其允许使用拖拉的方式在
IDE
的设计视图中快速创建包含
Ajax
功能的组件;同样的,
Java
领域的
JSF
、
Tapestry
等框架也提供了类似的组件。这些组件提供了快速开发
Ajax
应用的另一捷径。
在接下来的内容中,我们选取当前比较流行的三个开源程序包和框架,来体验一下
Ajax
的魅力。
(作者介绍:柯自聪,软件工程师,专注于
Web
应用程序开发,关注
OA
、门户、电子政务、电子商务领域,著有《
Ajax
开发精要
--
概念、案例与框架》一书以及《
Ajax
开发简略》、《
Liferay Portal
二次开发指南》等开源文档。)
二
Prototype
2.1
什么是Prototype
Prototype
是由
Sam Stephenson
开发的一个
Javascript
类库,也是其他框架的鼻祖。其对现有的部分
Javascript
对象比如
Object
、
Function
、
Dom
、
String
等进行扩展,并且对
Ajax
应用进行封装,借此提供了兼容标准的更加易于使用的类库,极大的方便开发人员快速创建具备高度交互性的
Web2.0
胖客户端应用程序。
Prototype
最初的目标是应用于
Ruby
领域的,不过由于优秀的表现和完美的封装以及服务器语言无关性,现在已经被应用到各个领域,包括
Java
、
.NET
、
PHP
等。不过在
Prototype
的源码中,还是可以找到
Ruby
的影子,比如
Ruby
样式的
Array
对象枚举。
正如之前提到的,
Prototype
是一个底层的远程调用包,虽然其仅仅是一个千余行的
Javascript
文件,但是它为其他框架提供了最底层的
Javascript
扩展和
Ajax
封装。其他
Javascript
程序库在其基础上构建了更加高级的功能和
UI
效果,比如
Script.aculo.us
。
Prototype
目前的最新版本是
1.4
,
1.5
也已经提供了
pre
版本,其官方网站提供了最新版本的下载,包括
zip
包、
js
文件和
Subvision
源码。不过和其他版本一样,
Prototype
官方网站并未提供完整的参考文档,开发者只能通过阅读源码掌握其功能。可喜的是,网上已经流传着不少关于
Prototype
源码解读和使用的文档,这在一定程度上弥补了
Prototype
官方文档不足的遗憾。
2.2
软件组织架构以及应用
Prototype
主要包括三个内容:一是提供了一些全局性的函数,替代原先烦琐重复的代码;二是对现有
Javascript
、
DOM
对象的扩展,提供访问公共函数的捷径;三是对
Ajax
应用的封装,使得开发
Ajax
应用更加容易和快速。
全局性的函数,比较有代表性的
$
系列函数和
Try.these()
函数。
$()
函数是用于替代在
DOM
中频繁使用的
document.getElementById()
方法的,其返回参数传入的
id
所指向的元素。不过,其允许传入多个
id
作为参数,然后返回一个其
id
指向的元素的
Array
对象。
$F()
函数则用于返回任何表单输入控件的值,比如文本框、文本区域、下拉列表,其也是以元素的
id
或者元素本身作为参数。不过,必须注意的是,
id
所指向的元素必须支持
value
属性,比如文本框。如果
id
指向一个按钮,那自然就得不到所要的
value
值。
$A()
函数能够将其接受到的任何可枚举列表转化成为一个
Array
对象,比如将
string
字符串转化成
Array
数组。
$H()
函数则将传入的对象转换成一个可枚举的和联合数组类似的
Hash
对象。
$R()
函数是
new ObjectRange(lowBound, upperBound, excludeBounds)
的缩写和替代。
Try.thiese()
方法以一系列的函数作为参数,按照顺序一个一个的执行,返回第一个成功执行的函数的返回值。这使得想调用不同的方法直到其中一个成功执行的需求变得容易和直观。否则我们就得变通的用
if else
去判断了。典型的比如在保证浏览器兼容的情况下实例化
XHR
对象。
Prototype
对
Javascript
的
Object
、
Number
、
Function
、
String
、
Array
、
Event
等对象进行了扩展,创建了一些新的对象和类,并在此基础上提供了很多有用的公共函数,比如
each()
、
any()
、
collect()
等。
Prototype
另外一个值得称道的是对
Ajax
的封装和简化,这也是
Prototype
吸引我们的另外一个重要之处。
Prototype
的
Ajax
功能主要由
Ajax.Request
和
Ajax.Updater
两个类完成。
在没有使用
Prototype
之前,我们需要创建
XHR
对象实例并且异步的跟踪其进程,在回调函数中使用
DOM
解析其返回的响应数据并且处理后更新页面。而
Ajax.Request
类提供了完成这一系列步骤的捷径。我们只需要将目标
URL
、
URL
参数、
http
请求方法类型、回调函数名称等一股脑的传递给
Ajax.Request
类即可。
Ajax.Request
类是针对需要解析服务器返回的响应数据的情况。而如果服务器返回的信息已经是
HTML
格式,只需要填充到某个
HTML
控件中,则可以使用
Ajax.Updater
类。其调用
innerHTML
直接将
HTML
代码填充到指定的
HTML
控件内部。
难得可贵的是,以往我们需要判断
XHR
的
readyState
和
status
值来获取
http
请求的状态并且作出相应的处理,以便应付请求失败的情况;而
AjaxRequest
和
Ajax.Updater
类提供了
onComplete
来替代这些烦琐的判断,其只需要简单的在请求的选项参数中的名为
onXXXX
属性
/
方法中提供自定义的方法对象即可。
接下来,我们使用
Prototype1.4
,列举一二,体验一下
Prototype
的主要功能及其所带来的便捷。
从
Prototype
官方网站
http://prototype.conio.net
下载最新的开发包
prototype-1.4.0.js
,放到应用程序目录中,通过
<script>
代码引入
Prototype
程序库:
<script language="javascript" type="text/javascript" src="prototype-1.4.0.js"></script>
2.3.1
$
系列函数体验
在
Prototype
出现之前,我们使用这种方式定位页面上的某个
HTML
元素及其值:
var myElement = document.getElementById(“your element’s id”);
var myValue = document.getElementById(“your element’s id”).value;
现在,可以分别使用
$()
函数和
$F()
函数来代替,例程
1
展示
$()
和
$F()
函数的用法:
var myElement = $(“your element’s id”);
var myValue = $F(“your element’s id”);
例程
1
:
$()
和
$F()
函数的用法
<p>Username:<input type="text" name="txtUsername" value="Jimmy"></p>
<p>
<input type="button" name="$Test" value=" $ " onClick="window.alert($('txtUsername'))">
<input type="button" name="$FTest" value=" $F " onClick="window.alert($F('txtUsername'))">
</p>
$A()
函数则将其接收到的可枚举的任何参数转化成为一个
Array
对象。结合
Prototype
对
Array
的扩展,
$A()
能够提供更加强大的功能。例程
2
使用
$A()
函数获取页面中的全部
input
类型的控件,并使用扩展后的
each()
函数遍历全部的控件。
例程
2
:
$A()
函数的用法
<script language="javascript" type="text/javascript">
/*$A
函数体验
*/
function do$ATest() {
var nodeList = document.getElementsByTagName("input");
var nodeArray = $A(nodeList);
var message = "
全部
input
控件:
\r\n";
nodeArray.each(
function(node) {
message += node.type + "|" + node.name + "|" + node.value + "\r\n";
}
);
window.alert(message);
}
</script>
<input type="button" name="$ATest" value=" $A " onClick="do$ATest()">
2.3.2
Try.these()
函数的妙用
我们知道,
XHR
是
Ajax
的核心之一。但是各个浏览器对
XHR
的实现不同,
IE
浏览器的各个版本对
XHR
的支持也有所差异。为了保证
Ajax
的浏览器兼容性,在实例化
XHR
对象的时候,通常要使用
try/catch
对兼容性进行判断。比如例程
3
所示。
例程
3
:使用
try/catch
块实例化
XHR
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
if(xhr.overrideMimeType) xhr.overrideMimeType(“text/xml”);
}
else if(window.ActiveXObject) {
try {
xhr = new ActiveXObject(“Msxml2.XMLHTTP”);
}catch(e) {
try {
xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
}catch(e){}
}
}
而现在,使用
Try.these()
函数,这些烦琐的过程变得异常简单。
例程
4
:使用
Try.these()
函数实例化
XHR
function doInitialXHR() {
return Try.these(
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
function() {return new ActiveXObject('Microsoft.XMLHTTP')},
function() {return new XMLHttpRequest()}
) || false;
}
2.3.3
对集合类的遍历
之前提过,
Prototype
最初的应用领域是
Ruby
。
Ruby
为遍历集合中的元素提供了一系列快捷的方法,使得执行维护、查找、收集、删除其中的元素更加快速。
Prototype
新建了一个
Enumerable
对象,为
Javascript
提供类似
Ruby
的功能。
在
Ruby
、
.NET
语言中,都支持使用
each
关键词对集合中的元素进行遍历。在
Enumberable
对象中,还有很多方法比如
all()
、
any()
、
collect()
等都是基于
each()
方法实现的。所以,
each()
方法是操作集合元素的基础。
each()
方法使用
iterator
依次获取集合中的每个元素,并将其作为匿名函数的参数;也可以在该匿名函数中加上可选参数
index
,获取当前元素的索引值。其实在例程
2
中,我们已经使用了
each()
方法。
例程
5
使用
each()
方法,对一个保存货物价格的数组进行遍历,显示价格及其索引值。
例程
5
:使用
each()
方法遍历集合
function doEachTest() {
var prices = [100.2, 445, 552.3, 56.0];
prices.each(
function(price, index) {
window.alert("Value:" + price + "| Index:" + index);
}
);
}
2.3.4
P
rototype
的Ajax体验
Prototype
将
Ajax
应用封装为
Ajax.Request
和
Ajax.Update
类。使用这两个类,可以应付大部分的
Ajax
应用,而且不需要烦琐的实例化
XHR
、监控请求状态的过程。
假设我们将书籍的信息保存在一个
XML
文档中,如例程
6
所示。
例程
6
:保存书籍信息的
XML
文档
<?xml version="1.0" encoding="gb2312"?>
<books>
<book>
<title>Ajax bible</title>
<pages>500</pages>
</book>
<book>
<title>Build with Ant</title>
<pages>632</pages>
</book>
<book>
<title>Google</title>
<pages>934</pages>
</book>
</books>
现在,我们使用
Ajax.Request
类去获取这个
XML
文档的内容,并将其显示出来。例程
7
展示了这一过程。
例程
7
:使用
Ajax.Request
获取
XML
文档内容
<script language=”javascript” type=”text/javascript”>
/*Ajax.Request
类体验
*/
function doAjaxRequest() {
var url = "books.xml";
var myAjax = new Ajax.Request(
url,
{
method:"get",
onComplete:showResponse
}
);
}
/*Ajax.Request
类回调函数
*/
function showResponse(request) {
window.alert(request.responseText);
}
</script>
<input type="button" name="ajaxRequest" value="ajaxRequest" onClick="doAjaxRequest()">
图
1
展示了使用
Ajax.Request
后所获取的
books.xml
文档内容。
图
1
使用
Ajax.Request
后所获取的
books.xml
文档内容
例程
7
中,
onComplete
指定的
showResponse
函数其实是
Ajax
的回调函数,通常在这个回调函数中完成对响应数据的解析和显示。而如果服务器端返回的是已经格式化后的
HTML
代码(这点在
Ruby
中很流行),则可以使用
Ajax.Updater
。例程
8
使用
Ajax.Updater
将服务器的响应数据填充到指定的
div
中。图
2
展示了使用
Ajax.Updater
的执行效果。
例程
8
:使用
Ajax.Updater
获取服务器的响应数据
<script language=”javascript” type=”text/javascript”>
/*Ajax.Update
类体验
*/
function doAjaxUpdate() {
var url = "response.jsp";
var pars = "field=all&show=true";
var myAjax = new Ajax.Updater(
"divContent",
url,
{
method:"get",
parameters:pars
}
);
</script>
<input type="button" name="ajaxUpdate" value="ajaxUpdate" onClick="doAjaxUpdate()">
<p><div id="divContent"></div></p>
图
2
使用
Ajax.Updater
的执行效果
例程
9
是例程
8
所请求的
JSP
文件。其简单的打印出加粗后的“
Ajax.Update
”字样。
例程
9
:
<%@ page contentType="text/html; charset=gb2312"
language="java" import="java.sql.*" errorPage="" %>
<%="<strong>Ajax.Update</strong>"%>
三
Dojo
3.1
什么是Dojo
Dojo
是一个底层的
Javascript
工具包,其设计的目的是要使
Web
应用程序中增加动态特性更加容易和快捷。其提供了很多漂亮的窗口部件和
UI
效果,比如控件的浅入浅出、移动、拖拽、擦除、树菜单、内容面板、标签面板、面板容器、
Windows
窗口、向导窗口等等。
Dojo
所提供的强大的可靠的组件,可以使
Web
应用程序具备更加优秀的用户体验效果,响应更快,功能更多。
与
Prototype
相比,
Dojo
提供了更完善丰富的文档。除了完整的
Doc
文档和
API
参考,
Dojo
还提供了丰富的
Demo
示例,使得用户更真切的体会到
Dojo
的应用效果。
与
Prototype
不同的是,
Dojo
本身实现了很多
UI
效果,比如浅入浅出,而这些效果在
Prototype
是由其额外的扩展实现比如
Script.aculo.us
实现的。
Dojo
的最新版本是
0.3.1
。我们可以从其官方网站下载到最新的
zip
开发包,其中包含了丰富的
demo
示例。
3.2
软件组织架构以及应用
Dojo
是由多个包组成的,其中包括:
ü
dojo.io
:对
Ajax
应用进行封装,提供简单的
API
实现
Ajax
功能。
ü
dojo.event
:提供浏览器兼容的事件体系。
ü
dojo.lang
:用于支持混合(
mixins
)及扩展对象。
ü
dojo.graphics
:用于实现优秀的
HTML
特效功能,比如浅入浅出、移动等等。
ü
dojo.dnd
:用于支持拖拽功能。
ü
dojo.animation
:用于支持动画效果的创建。
ü
dojo.hostenv
:用于提供
Javascript
扩展,比如提供
import/includes
替换原有的
src
属性。
对于
Ajax
应用来说,
Dojo
将其封装为一个简单的方法,
dojo.io.bind(request)
。其以一个
dojo.io.Request
对象作为输入参数,这个
dojo.io.Request
对象封装了所有的
Ajax
操作信息,比如目标
URL
、请求类型、
mimetype
、是否采取异步操作、回调函数等等。
dojo.io.Request
对象比较常用的属性包括:
url
:
Ajax
操作将提交
http
请求的目标
URL
;
mimetype
:
http
请求的
mime
类型,默认为
text/plain
;
method
:
http
请求的类型,
get
或者是
post
;
formNode
:
http
请求中使用的表单节点;
content
:将附着在
http
请求中传递给服务器的内容;
changeUrl
:
Ajax
操作完成后将替换当前
URL
的新
URL
;
useCache
:是否使用
Dojo
提供的缓存;
load
:指定
Ajax
的回调函数;
error
:指定
http
请求发生错误时要调用的函数;
timeout
:指定
http
请求超时时要调用的函数;
除了
Ajax
封装外,
Dojo
所提供的窗口部件和
UI
效果也同样引人注目。图
3
和
4
展示了其中的两个
UI
效果。
图
3 Dojo
所实现的标签面板
图
4 Dojo
所实现的仿
Windows
窗口
从
Dojo
的官方网站
http://dojotoolkit.com
下载最新的
Dojo
的
zip
开发包
dojo-0.3.1-ajax.zip
,解压后的文件夹包含
demos
、
release
、
src
、
tests
子文件夹以及
dojo.js.uncompressed.js
、
dojo.js
等文件。其中,
dojo.js.uncompressed.js
是未经过压缩和代码混淆的
Dojo
程序包,
dojo.js
则是压缩后的
Dojo
程序包。两者在使用上没有任何差异,不过要研究源码还是参考前者为好。
将
dojo.js
拷贝的程序目录,通过
<script>
代码引入:
<script language=”javascript” type=”text/javascript” src=”dojo.js”></script>
3.3.1
Dojo
的Ajax体验
之前提到,
Dojo
将
Ajax
应用封装为一个简单的方法调用
dojo.io.bind()
。这里,我们使用
dojo.io.bind()
来替换例程
7
所实现的功能:获取并显示服务器端的
xml
文档。
dojo.io.bind()
封装了
Ajax
的远程调用功能,其获取一个
hash
列表参数,随后使用这个参数初始化
XHR
对象,然后在其本身注册指定的回调函数。例程
10
展示了使用
dojo.io.bind()
实现例程
7
所示功能的过程。
例程
10
:使用
dojo.io.bind()
请求服务器的
XML
文档
<script type="text/javascript">
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
/*
使用回调函数显示响应数据
*/
function doDojoBind() {
var url = "books.xml";
dojo.io.bind({
url:url,
load:function(type,data,evt) {showResponse(data);},
error:function(type,error) {},
mimetype:"text/plain"
});
}
/*dojo.io.bind
使用的回调函数
*/
function showResponse(data) {
window.alert(data);
}
</script>
<input type="button" name="dojoIoTest" value="dojo.io.bind()" onClick="doDojoBind()">
四
DWR
4.1
什么是JSON和DWR
在
Ajax
应用中,我们经常使用
XML
文档来组织服务器的响应数据。虽然
XML
文档在范式统一和数据表示等方面有不可比拟的优势,不过将其应用于
Javascript
代码中之前,必须经过
DOM
解析。
JSON
(
Javascript Object Notation
)是一种用简单文本描述
Javascript
对象的开放格式标准,其使用
Javascript
数组直接量的格式来组织数据,相对
XML
文档而言更易于组织和解析,而且很容易将
JSON
对象直接转化成为
Javascript
对象。比如例程
6
所示
XML
数据可以很直观的用
JSON
格式表示,如例程
11
所示。这样我们就可以很直观的用
doc.books[0].title
来获取第一本书的标题。
例程
11
:用
JSON
替代
XML
文档表示数据
var doc =
{"books":
[
{
"title":"Ajax bible",
"pages":500
},
{
"title":"Build with Ant",
"pages":632
},
{
"title":"Google",
"pages":934
}
]}
如果要在
Ajax
应用程序中使用
JSON
,只需要以
JSON
格式组织服务器的响应数据,
XHR
以文本的形式接收数据,则处理响应数据无需特定的数据解析器即可以使用
Javascript
操作数据了。
DWR
(
Direct Web Remoting
)是
getahead
公司开发的一个基于代理模式的
Ajax
应用框架,其允许客户端
Javascript
远程调用服务器端的
Java
类方法,执行相应的事务操作,就好像
Java
类是在本地客户端上一样。
DWR
使用自身的
API
,将远程服务器上的
Java
对象或者列表格式数据转化成为
JSON
格式的
Javascript
本地对象,以供本地客户机调用。
使用
DWR
可以有效的从应用程序代码中把
Ajax
的全部请求
-
响应循环代码消除掉,即客户端再也不需要直接处理
XHR
对象,不再需要编写对象的序列化代码或者使用第三方工具才能将对象转化成
XML
,甚至不再需要编写
Java
代码将
Ajax
请求调整成对
Java
对象的调用。
DWR
最新的版本是
1.1
,其官方网站
http://getahead.ltd.uk/dwr/overview/dwr
提供了丰富的介绍、安装、部署文档以及足够的
demo
程序包。
4.2
软件组织架构以及应用
DWR
的结构主要包含两部分,一是运行再浏览器客户端的
Javascript
,其被用于与服务器通信;二是运行于服务器端的
Java Servlet
,其被用于处理请求并将响应结果转化为相应的格式回传给浏览器。
DWR
采取一种动态生成基于
Java
类的
Javascript
代码的新方法来实现和处理
Ajax
。这样,
Web
开发人员就可以在
Javascript
中像使用本地浏览器代码一样使用
Java
代码,而实际上这些
Java
代码是运行于服务器端的并且可以自由访问
Web
服务器资源的。只是出于安全考虑,
Web
开发者必须适当的配置,决定哪些
Java
类可以安全的被客户端调用。
图
5
展示了
DWR
如何利用一些类似
Javascript
的
onClick
等事件的结果来改变一个下拉框列表的内容。这个事件处理器调用一个
DWR
生成的
Javascript
函数,它和服务器端的
Java
函数是匹配的。
DWR
接着处理了
Java
和
Javascript
之间的所有远程信息,包括转换所有的参数和返回需要的值。接着
DWR
执行了相应的回调函数(
populateList
)。这个例子演示了如何使用
DWR
功能函数来改变网页内容。
图
5
DWR
交互过程
DWR
是作为
Web
应用程序中的
servlet
部署的。把它看作一个黑盒子,这个
servlet
有两个主要作用:首先,对于公开的每个类,
DWR
动态地生成包含在
Web
页面中的
Javascript
。生成的
Javascript
包含存根函数,代表
Java
类上的对应方法并在幕后执行
XMLHttpRequest
。这些请求被发送给
DWR
,这时它的第二个作用就是把请求翻译成服务器端
Java
对象上的方法调用并把方法的返回值放在
servlet
响应中发送回客户端,编码成
Javascript
。
DWR
还提供了帮助执行常见的用户界面任务的
Javascript
工具函数。
有两种方式可以开始
DWR
的应用。一种是直接从其官方网站下载
DWR
的
Web
应用示范包,这是一个
war
的部署包,从中可以对
DWR
的应用效果及其部署方式有一个大概的了解。不过这种方式无法详细掌握如何将
DWR
与
Web
应用程序紧密集成。另外一种方式是根据
DWR
官方开发文档的讲解,通过一步步的部署和配置,将
DWR
集成到
Web
应用程序中。本节通过简单的示范和一个例子,讲述
DWR
的部署和集成。
DWR
采用一个
Java Servet
来处理请求并将响应结果发送给浏览器,这个
Java Servlet
需要加入到
Java Web
应用程序的部署描述文件
web.xml
。其次,其通过一个自定义的部署描述文件
dwr.xml
,控制
Java
对象与
Javascript
的转化。
第一步:安装
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
也可以从随书光盘
software
目录中找到。
第二步:修改
web.xml
,添加
Servlet
映射
修改
{APPLICATION_WEB_HOME}\WEB-INF
目录下的
web.xml
,将下列代码添加到
web.xml
的适当位置:
例程
12
:为
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>
<servlet-name>dwr-invoker</servlet-name>
<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
部署描述文件,其代码例程
13
所示:
例程
13
:
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
名称还是有些限制的:
l
避免使用
Javascript
关键字或者保留字,因为这些用
Javascript
关键字或者保留字命名的方法会自动执行。大部分的
Javascript
关键字或者保留字也是
Java
的关键字或者保留字,比如“
try
()”不是一个合法的命名。不过还是有一部分的
Javascript
关键字或者保留字在
Java
中不被限制,比如“
delete
()”。
l
避免使用方法重载。这些重载的方法被调用的是时候有时候会引起麻烦,因为
Javascript
没有像
Java
那样的包命名机制来支持方法重载。
第四步:测试
URL
,查看部署效果
在浏览器地址栏中输入
http://localhost:8080/ajaxlab/dwr
,其页面效果应该如图
6
所示。通常,这个页面会显式在
dwr.xml
部署描述文件中定义的全部
Java
类,并且显式可以查看所有其可供远程调用的方法的列表的链接。这个页面有
DWR
动态创建。在本例中,页面上有一个
JDate
的链接,列出暴露给
DWR
的
JDate
类可供
Javascript
远程调用的方法。
图
6
DWR
部署效果
点击“
JDate
”链接,查看
Javascript
能够调用的
java.util.JDate
类的方法,其效果如图
7
所示。单击每个方法后面的“
Execute
”按钮,尝试执行这些方法。
图
7
能够被
Javascript
远程调用的方法
第五步:
使用
Javascript
远程调用
Java
类的方法
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>
例程
14
展示了这个过程,调用
java.util.Date
类的
toString
()方法将当前时间打印出来。这里例子包含一个普通按钮控件和两个
Javascript
函数,其中一个函数
doTest
通过
JDate.toString
()调用,取得
java.util.Date
所表示的当前时间。第二个函数
responseDate
将第一个函数所取得的当前时间以弹出窗口的形式显式出来。第二个函数的名称作为第一个函数的参数,这个类似第5章所说的回调函数。具体代码如下,其运行效果如图
8
所示:
例程
14
:
sample12_1.jsp
<%@ page contentType="text/html; charset=gb2312" errorPage="" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Ch12--DWR
使用入门
</title>
<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>
<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>
图
8
调用
JDate
的
Javascript
方法显示当前时间
五
其他开源框架
AjaxAnywhere
是
sourceforge.net
另外一个开源的
Ajax
项目,其设计的初衷是要将已有的
JSP
和
JSF
组件转换成为具备
Ajax
功能的组件,而且这一转换过程不需要复杂的
Javascript
编码。与其他解决方案项目,
AjaxAnywhere
不是基于组件的,比如在
AjaxAnywhere
就找不到类似
Ajax Tags
的输入自动完成(
auto-complete
)组件。
使用
AjaxAnywhere
可以将页面简单的划分为多个区域(
zone
),然后调用
AjaxAnywher
刷新(
Refresh
)那些指定的区域,而不是整个页面。
AjaxAnywhere
使用“分区刷新”的思路,其工作原理如下:
1
、使用
AjaxAnywhere
自定义标签库将一个
Web
页面划分为几个可重载的区域(
reload-capable zones
)。
2
、使用
AjaxAnywhere Javascript
应用编程接口(
API
)替代传统通信机制下表单提交方式。
3
、当请求在服务器端处理的时候,决定那些页面区域可以刷新(
refresh
)。这个过程可以使用基于客户端的
Javascript
或者基于服务器端的
AjaxAnywhere
应用编程接口(
API
)。
4
、在服务器端,
AjaxAnywhere
会生成包含即将更新的
HTML
代码的
XML
文档。
5
、在客户端,
AjaxAnywhere Javascript
接受这个
XML
文档,解析文档,并更新指定的页面区域。
采取这样的设计思路,可以尽可能的降低
Javascript
代码量,降低
Ajax
的开发门槛:
ü
不需要掌握和开发那么多的
Javascript
代码。
由于缺乏被广泛接受的命名习惯、格式化规则和模式,使得
Javascript
编码相对
Java/JSP
复杂许多。尤其在浏览器兼容性方面缺乏有效的调试和单元测试手段。使用
AjaxAnywhere
可以摆脱这些
Javascript
的复杂性。
ü
方便集成。
使用
AjaxAnywhere
不需要改变底层的应用程序代码。
ü
降低技术风险。
可以随时在传统的通信机制和
Ajax
之间切换,允许
Web
应用程序同时支持两种通信机制。
ü
平滑的兼容性。
再也不用在使用
Ajax
还是传统的交互方式间摇摆了,使用
Ajax AnyWhere
的
Web
应用程序可以兼容两种请求方式。
AjaxAnywhere
的客户端脚本经过了
IE
、
Mozilla Firefox
和
Opera
等浏览器的兼容性测试,能够最大程度的保证代码的浏览器兼容性。
另外,还需要注意的
AjaxAnywhere
特性是,
Ajax
接收到的
Ajax
代码采用特殊的方式处理。
AjaxAnywhere
通过
eval(“”)
的方式执行这些
Javascript
代码,也可以将所定义的
Javascript
函数保存在适当的上下文(
Context
)中。不过,在允许
Ajax
方式重载的页面区域,不允许执行
document.write()
之类的
Javascript
语句。
允许重载的区域可能在提交请求之前就确定了,这种情况下需要重载客户端的
AjaxAnywhere.getZonesToReload()
的
Javascript
函数,不需要额外的服务器逻辑处理。
如果希望
AjaxAnywhere
重载整个文档,则重载后的
AjaxAnywhere.getZonesToReload()
函数必需返回“
document.all
”字符串。也可以在服务器端调用
AAUtils.setRefreshAll(true)
刷新整个页面。
相应的,
Ajax
请求中的
response.sendRedirect()
会被转化成
Javascript
代码的
location.replace()
命令。
5.2
Ajax
Tags
Ajax Tags
是一组
Jsp
标签,用来简化
Ajax
技术在
JSP
页面中的使用。其提供了一些常见功能的标签如下拉列表级联选择,用户在文本框中输入字符自动从指定的数据中匹配用户输入的字符(
Google Suggestion
功能,输入建议)等。整个
Ajax Tags
构建在
JavaScript
框架之上。本节将简要介绍
Ajax Tags
,包括其提供的几个
Ajax
标签,并利用这些标签构建几个简单的应用。
Ajax Tags
是位于
sourceforge.net
上面的一个开源
Ajax
项目,其出发点在于应用标签封装的思想,实现一些常用的
Ajax
应用,提高开发效率。
Ajax Tags
提供一系列的标签,简化在
JSP
页面中使用
Ajax
的过程。
Javascript
在
Ajax
中占很大的比重,但实际上不少服务器端的开发人员掌握的
Javascript
知识并不完整(按照正常分工,页面构建应该是网页设计人员或者前端开发人员的职责)。
Ajax Tags
提供的标签,能够让开发人员将
JSP
页面与
Ajax
应用快速的集成整合。
Ajax Tags
支持如下情况下的无刷新页面更新:
ü
基于文本框的输入自动完成(
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
以上版本环境下运行。
SWATO
(
Shift Web Application To
……)是一组可复用的易集成的
Javascript/Java
库,可以快速的使
Web
应用程序的交互方式转变成
Ajax
方式。其主要特点有:
ü
通过
SWATO
,服务器端的
Java
库可以很方便的部署在支持
Servlet 2.3
的服务器上。
ü
其客户端的
Javascript
库可以运行在多种支持
XMLHttpRequest
的浏览器上。
ü
其使用
JSON
方法编组服务器上的
POJO
数据,很容易在任何
Javascript
环境中操作远程
POJO
对象,不管是使用硬编码还是与其他
Javascript
库集成。
ü
其提供简单的接口,使客户端的
Javascript
可以直接操作服务器上暴露给客户端的
POJO
对象。
ü
其使用多个可复用的控件(
Javascript
模版、
Javascript
日志等),使开发
Web
应用程序更加容易。
其提供简单灵活的在
web.xml
中配置使用
Servlet
和
Filter
(过滤器)的方式,集成
Spring
。
与
DWR
类似,
SWATO
提供了通过客户端
Javascript
直接调用远程服务器端
Java
对象和
EJB
接口的实现。不同的是,
SWATO
使用
JSON-RPC-Java
机制来实现客户端
Javascript
远程调用服务器端
Java
和
EJB
接口。
在
SWATO
中,客户端接受的数据可以是
JSON(SWATO
的后台是直接把
Java
对象映射成
JSON)
,也可以是
XML(
你可以从远端
URL
中获取
XML,
它在
SWATO
客户端引擎中被转化为
JSON)
。所以对于开发人员来说,它在客户端所要关心的只是
JavaScript
对象。
(
结构与
Java
对象或
XML
结构对应
)
。然后利用
SWATO
提供的一些视图组件
(AutoSuggest, Select, Form)
进行渲染。对于自定义性比较强的视图控件,你可以在前端使用
Template
引擎
(来自
TrimPath,
类似于
Velocity
的简单语法),甚至可以把它封装成你自己的组件,只要在其中实现
gotResult
与
gotError
函数,便可以很轻松的与
SWATO
远程调用功能集成。
六
推荐书目(按出版顺序排列)
国内出版的第一本
Ajax
书籍,重点介绍
Ajax
及相关的工具和技术,主要内容包括
XHR
对象及其属性和方法、发送请求和处理响应、构建完备的
Ajax
开发工具、使用
JsUnit
测试
JavaScript
、分析
JavaScript
调试工具和技术,以及
Ajax
开发模式和框架等,适合作为
Ajax
的入门书籍阅读。
Amazon.com
畅销书,目前
Ajax
领域最全面深入的著作。其中不仅有对于基础知识的介绍,还有对于
Ajax
开发中重大的体系架构问题的深入探讨,总结了大量
Ajax
开发中的设计模式,并讨论了框架、安全性与性能等等。书中提供了几个典型的例子,兼顾各种开发平台,这些例子的代码稍作修改就可以直接应用于项目开发之中。
6.3 Ajax
修炼之道Pragmatic Ajax-Web2.0入门
原书作者是
Ajaxian.com
的创始人,
JavaOne
、
TheServerSide
等诸多高级别会议的演讲者。本书作为
Pragmatic
系列之一,从实践出发,通过实例展示
Ajax
的诸多特性,手把手教你实现
Google Map
的绚丽效果。不仅教会你
Ajax
的技术细节,同时还带你了解各种功能强大的主流
Ajax
工具包(
Dojo
、
Prototype
、
Script.aculo.us
、
DWR
、
Backbase
、
SmartClient
、
Ajax.NET
、
SAJAX
、
JSON-RPC
),掌握
Ajax
实时查看源代码的方法以及进行代码调试的相应方法,学习
Ajax
的开发模式和框架。本书后半部分共用了五个章节,从服务器端编程的角度,详细讲述了
Ajax
同
PHP
、
Ruby On Rails
、
Java
和
.NET
等语言的融合,最后还介绍了与
Ajax
相类似的其他
RIA
技术以及
Ajax
的精彩未来(
E4X, Canvas, SVG,
的相关应用)。本书秉承了《程序员修炼之道》的特点——
“从小工到专家”,各个层次的
web
开发人员都能从本书中获益匪浅。
本书从概念、案例与框架三个角度来详细阐述
Ajax
开发技术,先介绍
Ajax
的由来、优势及其在
Web
开发中的地位,接着详细介绍
Ajax
的各项组成技术、封装、开源和商业框架等各种相关知识,并提供丰富实用的开发案例和综合案例,引导读者一步步地了解并掌握利用
Ajax
进行
Web
应用程序开发的方方面面。
本书是关于
Ajax
技术、模式和使用场景的开发人员级教程,不仅介绍了
Ajax
的基本知识,还讨论了
Ajax
模式和框架,同时针对
XML(
包括
XPath
和
XSLT)
、
RSS
/
Atom
、
Web
服务、
JSON
和
Web
用户界面组件等主题,阐述了如何将
Ajax
与这些技术有效地结合在一起,并给出了一个使用
Ajax
开发的
Web Mail
系统完整实例。书中经典的实例、完整的源代码,都将给读者带来“实战”的指导。
七
参考资源网站
7.1
Ajax
: A New Approach to Web Applications
http://www.adaptivepath.com/publications/essays/archives/000385.php
点评:
Jesse James Garrett
在这篇文章中第一次将这种融合多种技术的综合技术简称为
Ajax
。在这篇文章中,
Jesse James Garrett
分析了现有
Web
应用程序的缺陷,定义了
Ajax
各个组成技术的职责,并且说明
Ajax
为何如此不同,
Ajax
都应用在什么地方。最后,
Jesse James Garrett
给出一份
FAQ
,解答人们对
Ajax
的各种问题。
http://dojotoolkit.com
http://prototype.conio.net
http://getahead.ltd.uk/dwr/overview/dwr
http://script.aculo.us
http://json-rpc.org
http://www.open-open.com/67.htm
点评:
open-open.com
一个专门收集
Java
领域开源项目的网站。其将各个开源项目分门别类,提供项目介绍和导航。该页面介绍了当前大部分的
Ajax
开源项目,从中可以一窥
Ajax
开源的大致现状。
http://www.ajaxcn.org
点评:《
Ajax
实战》一书的译者,国内最早关注
Ajax
应用的群体之一。站点上包含了大量介绍
Ajax
技术以及
Ajax
应用心得和经验的文章,值得
Ajax
开发人员参考和借鉴。
7.9
Ajax
Pattern
http://ajaxpatterns.org/
点评:
AjaxPatterns.org
是一个收集
Ajax
设计模式的站点,其已经发展成为
Ajax
技术的
WIKI
,内容涉及
Ajax
设计模式、
Ajax
书籍介绍、页面架构、框架、工具等等,是跟踪
Ajax
技术、提高
Ajax
开发设计水平的理想场所。