AJAX设计策略(全)
内容
-概况
-什么是
AJAX
-
AJAX
技术
-
AJAX
和服务端技术
-设计策略
-设计策略
1
:自己完成(
Do It Yourself
)
-设计策略
2
:使用客户端
JavaScript
库
-设计策略
3
:使用客户端框架
-设计策略
4
:包装
-设计策略
5
:远程调用
-设计策略
6
:所有
Java
技术
-其他信息
-关于作者
概况
受网站目标的驱使,
Web
应用已经进入了一个新时代,这些目标包括更快的响应用户动作,在创作和分享
web
内容时进行的用户协作等。被定义为此类高速响应的和经常协作站点的最流行的术语就是
Web 2.0
。
|
|
一些
web 2.0
的最经典的例子包括
Google Maps
和
Flickr
站点。
Google Maps
提供一个高速响应的用户界面(
UI
)。例如:你可以察看一副地图,并通过移动鼠标越过它以立即的察看相临近的区域。
Flickr
是这样一个网站,用户们存储和共享照片
--
用户管理几乎这个站点的所有内容。
另外的
Web2.0
站点通过一些方式提供相似的丰富的用户体验,这些方式包括整合其他网站的服务或合并一个稳定的新的信息流。例如,
Google map
服务可以被使用在另一个站点,比如一个汽车销售站点,用来显示一家销售指定汽车类型的代理商在地图上的位置。此类站点集成使用的术语叫做
” mashups”
。另外还包括一个运动导向网站,它可以不断的刷新分数而不需要用户请求页面更新。
这篇文章是关于现今用来制作高响应的
web 2.0
站点的主要技术:
Asynchronous JavaScript and XML (AJAX).
什么是
AJAX
?
许多优秀的文章都将
AJAX
描述为有效的,例如《
Asynchronous JavaScript Technology and XML (AJAX) With Java 2 Platform Enterprise Edition
》。简单说,
AJAX
是一系列使网页成为-或看起来像高速响应的技术。
AJAX
使这个成为可能,因为它支持网页的异步和部分刷新功能。
部分刷新意味着当一个交互事件发生-例如,用户向网页的表单里输入信息并且点击提交按钮-服务器处理信息并返回关于这些信息的有限响应。值得注意的,服务器并不返回整个页面,虽然返回整个页面已成为一种惯例,
“
点击,等待,刷新
”web
应用。相反的,客户端基于响应来更新页面。这意味着,只有部分页面被更新。换句话说,网页像一个模版一样被处理:客户端和服务端交换数据,客户端基于收到的数据来更新模版的某部分。可以这样认为,使用
AJAX
的
web
应用受事件和数据的驱动,而传统的
web
应用受页面驱动。
异步意味着在向服务端发送数据之后,当服务端在后台运行的时候,客户端可以继续执行。这意味这用户可以继续与客户端进行交互,而不必等待服务端的滞后响应。例如,用户可以继续在
Google map
上移动鼠标,并在显示器上看到一个平滑的,不间断的变换。客户端在继续执行之前不必等待服务端的响应。
AJAX
站点的另一个重要方面在于,触发
AJAX
响应的事件不限于提交数据或点击链接。在页面的一个区域上移动鼠标,在输入域中键入数据,或者像
Google Maps
一样用鼠标拖拽地图,已足够触发
AJAX
响应。用户和网页间的动态交互使
web
应用更接近于高速响应的桌面应用。桌面应用经常被称为胖桌面应用(
rich desktop applications
)。所以
web 2.0
经常被叫做胖互联网应用(
rich Internet applications
)。
AJAX
技术
下面的技术是
AJAX
里具有代表性的
:
层叠样式单(
CSS
),一种定义页面表示样式的语言,例如字体、颜色等。
JavaScript
,一种脚本语言。在
JavaScript
技术里对
AJAX
很关键的一个元素是
XMLHttpRequest
,一个用来在
web
客户端和
web
服务端交换数据的对象。
文档对象模型(
DOM
),提供页面的树状结构的逻辑视图。
XML
,用来从服务端向客户端传送数据的一种格式。尽管如此,你可以使用其他格式,例如
HTML, JavaScript Object Notation (JSON),
或无格式文本
.
像其他
web
应用一样,
AJAX web
应用使用
HTML
,
XHTML
类的标记语言来呈现页面,或者
JSP
类服务端技术来生成网页。另外,服务端应用系统在
AJAX
应用中扮演一个关键的角色。类似
Java EE
的服务端应用系统包括对关于
AJAX
的数据验证,用户身份管理,和持久性配置的很好支持。请看本文的
AJAX and Server-Side Java Technologies
部分。
| |
图
1: AJAX
如何处理用户动作
|
1.
用户在客户端生成一个事件。这导致了一个
JavaScript
调用。
2. JavaScript
函数在客户端创建和设定一个
XMLHttpRequest
对象,并且指定一个
JavaScript
回调函数。
3. XMLHttpRequest
对象向
web
服务端生成一个调用
—
一个异步的
HTTP
请求。
4. web
服务端处理请求并且返回一个包含结果的
XML
文档。
5. XMLHttpRequest
对象调用回调函数,呈现服务端的响应使得请求得到处理。
6.
客户端使用新数据更新描述页面的
HTML DOM
。
你可以通过多种方法将这些技术整合到
web
应用。例如,你可以在
HTML
页面里写
JavaScript
代码,或者你可以使用
Dojo toolkit
之类的库,它会提供你需要的部分或者全部的
JavaScript
功能。另外,你还有关于
AJAX
的服务器端的选择。
AJAX
和服务器端
JAVA
技术
所有的
AJAX
技术,同时也是客户端技术例如
JavaScript
、
XML
,都是关于客户端和服务端交互数据的。事实上
XMLHttpRequest
对象向服务端创建的请求是一个
HTTP
请求。对服务端来说,处理
AJAX
请求和处理传统
web
应用的
HTTP
请求没有不同-任何服务端技术都可以处理请求,包括
Java EE
的服务端
java
技术例如
servlets
,
JSP
技术,和
JavaServer Faces
技术。事实上,
Java EE
非常适合
AJAX
方法。
JavaServer Faces
和包含支持数据验证,用户身份管理,持久性的其他
Java EE
技术,非常适合于
AJAX
。
例如,你可以用
servlet
处理请求,管理客户端状态,访问企业资源,并为响应生成
XML
。或者你可以创建定制的
JavaServer Faces
组件进行服务端处理,也可以封装处理客户端的
Javascript
和
CSS
。
设计策略
作为开发者,你有很多个将
AJAX
置入
web
应用的选项。这些选项范围涉及从自己编写所有
AJAX
代码的
DIY
策略,到利用可以为你提供
AJAX
代码的库和框架。你可以多种策略。例如,你可以使用基于
JavaServer Faces
的客户端-服务端框架,并结合客户端的
javascript
库例如
Dojo
工具箱。
本文的剩余部分将讨论这样的一些设计策略并鉴定他们的优势的缺点。这些策略假定你在服务器端使用
Java EE
实现,例如
Sun Java Application Server
。
设计策略
1
:
自己完成(
Do It Yourself
)
走这条路,你自己编写所有代码来将
AJAX
置入
web
应用。这意味着你将编写客户端的所有
JavaScrip, CSS, and DOM
代码,和关于页面呈现的代码。在服务端,你编写处理
XMLHttpRequest
调用的代码,并返回适当的响应,比如
XML
。
让我们看一个将
AJAX
功能加入
web
应用的例子。例子发表在文章
"Creating an AJAX-Enabled Bookstore Application, a Do-It-Yourself Approach"
上。它那个例子基于
bookstore2
,是
Java EE 5 Tutorial
中
Duke's Bookstore
例子的其中一个。你可以在
Java EE 5 Tutorial
的
The Example JSP Pages
部分找到创建
bookstore2 web
应用的说明。
最初的
bookstore2web
表列了可以购买的书籍。用户和现在的
bookstore2
应用和交互是一个传统的同步交互。用户点击列表里书的标题进一步察看这本书的更多信息。这需要服务端完成所有的页面刷新。
这个发标在文章
"Creating an AJAX-Enabled Bookstore Application"
的例子添加了一些
AJAX
功能,是
web
应用能够弹出气球。添加的功能提供了更多的动态
UI
。当用户将鼠标越过表列的书目,关于书的细节将出现在弹出气球上,如图
2
所示。由于它是受
AJAX
驱动的,产生气球的用户和
web
应用间的交互是异步的。用户几乎即时的看到弹出气球-不需要等待服务端刷新整个页面。
图
2:
一个
AJAX
弹出式气球的
web
应用
|
回忆图
1
的步骤,在这里,
bookstore2 web
应用程序中
AJAX
的相关代码
1.
将事件映射到一个
JavaScript
函数
2.
创建和配置
XMLHttpRequest
对象
3.
通过
XMLHttpRequest
对象向服务端创建一个请求
4.
在服务端处理请求并返回一个包含结果的
XML
文档
5.
在
JavaScript callback()
函数中处理结果
6.
更新
DOM
用新数据呈现页面
附随
"Creating an AJAX-Enabled Bookstore Application"
这篇文章的是
AJAX bookstore2
应用程序文件。这些文件打包为一个
NetBeans IDE 5.5 web
应用项目。这篇文章将向你展示怎样打开和运行使用
NetBeans IDE 5.5
的项目。同时也展示怎样察看这些文件的内容。使用
NetBeans IDE 5.5
,你可以看到列出的每一步在代码是怎样实现的。
你会发现程序代码的主要部分是客户端 JavaScript 代码。例如,这里有一些 bookstore2 程序的 JavaScript 代码,它们创建和并配置了一个 XMLHttpRequest 对象,并用它向服务端组件创建了一个异步的请求。
bpui.alone.showPopupInternal=function(popupx, bookId) {
bpui.alone.req=bpui.alone.initRequest();
...
url="../PopupServlet?bookId=" + escape(bookId);
bpui.alone.req.onreadystatechange = bpui.alone.ajaxReturnFunction;
bpui.alone.req.open("GET", url, true);
bpui.alone.req.send(null);
}
...
bpui.alone.initRequest=function() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if (window.ActiveXObject) {
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
|
这里有
JavaScript
回调函数,处理异步请求响应的数据。注意,回调函数使用类似
getElementsByTagName()
的
DOM API
方法来提取
XML
中的数据。
inner.HTML
属性被用来更新页面的
DOM
呈现。
bpui.alone.ajaxReturnFunction=function() {
// statically setup popup for simple case
var componentId="pop0";
// check return of the call to make sure it is valid
if (bpui.alone.req.readyState == 4) {
if (bpui.alone.req.status == 200) {
// get results and replace dom elements
var resultx=bpui.alone.req.responseXML.getElementsByTagName("response")[0];
document.getElementById(componentId + "_title").innerHTML=
resultx.getElementsByTagName("title")[0].childNodes[0].nodeValue;
document.getElementById(componentId + "_message").innerHTML=
resultx.getElementsByTagName("message")[0].childNodes[0].nodeValue;;
// show popup with the newly populated information
document.getElementById(componentId).style.visibility='visible';
} else if (bpui.alone.req.status == 204){
alert("204 returned from AJAX call");
}
}
}
|
AJAX bookstore2 程序同样需要包含服务端组件的代码,例如 servlet -处理 XMLHttpRequest 并返回适当的响应。 "Creating an AJAX-Enabled Bookstore Application" 这篇文章同样分析 servlet 代码,和其他关于弹出式气球文件里的代码。
简言之, do-it-yourself 方式需要编写很大数量的 AJAX 相关代码来实现 bookstore2 程序的弹出式气球-其中有一些相当复杂。
Do-It-Yourself 方法的正面和反面
do-it-yourself approach 方法的确是将 AJAX 置入 web 应用的一种方法,但是它是最适合你的方法吗?这里有一些使用这种方法的优势(正面)和劣势(反面)。
正面
在 AJAX 处理上提供细密的控制,当你宁愿编写所有的 AJAX 相关代码而不使用 JavaScript 库或者其他能提供 AJAX 功能的方法,你可以明确的控制 AJAX 相关处理。你可以包含库没有提供或定制的功能,可以通过最适合你的方法使你的 AJAX 代码最优化。例如,你可以添加安全性控制或为性能而优化代码。
反面
需要很多的 AJAX 相关代码。如果你分析 bookstore2 里的代码,你将发现它需要很少的 AJAX 相关代码。如果其他方法提供你需要的 AJAX 功能并且需要很少代码,根据感觉使用这些方法。例如,类似在 Dojo 工具箱中的客户端 JavaScript 库,封装了一些类似创建和配置 XMLHttpObject 的 AJAX 操作,它们将减少你所需要编写的代码。如果库可以提供你需要的 AJAX 功能,使用它会比编码实现功能简单很多。请查阅本文的 Design Strategy 2: Use a Client-Side JavaScript Technology Library 部分。
需要若干种语言和技术的知识。 AJAX 代码需要你懂得 JavaScript , CSS ,和 DOM -这些对 Java 工程师来说并不是必须要懂的。其他方法,例如使用 jMaki 技术,允许你使用基于 Java 的技术整合 AJAX 功能。请看 Design Strategy 4: Do the Wrap Thing 部分。
需要开发者与浏览器的不兼容性斗争。尽管现在大多数的浏览器可以处理 AJAX 代码,不是所有的浏览器使用同一种方法处理 AJAX 代码。特别的,很多浏览器处理 JavaScript 代码的方式不同。值得注意的,对象 XMLHttpRequest 并不是 JavaScript 标准的一部分。事实上, IE 现在并不支持 XMLHttpRequest 对象。而是用 ActiveX 控件同服务器进行 AJAX 通信。这就是 bpui.alone.initRequest() 函数为什么包含下面的测试:
另外,你必须考虑浏览器不支持
AJAX
的所有可能性,例如一些老版本的浏览器。另一种办法,例如使用客户端
JavaScript
库,
jMaki, Direct Web Remoting (DWR),
和
the Google Web Toolkit (GWT)
会处理浏览器的不兼容性。请看本文的
Design Strategy 5: Go Remote
部分。
需要开发者与 UI 问题做斗争。 AJAX web 应用引入了许多 UI 问题。例如,你怎样为一个 AJAX 网页支持书签,如果他的内容经常改变但 URL 不会。你怎样为一个页面的特定状态做书签。另外,你怎样支持后退按钮?另一个简单的应用,开发者必须考虑这些 UI 问题并编写处理它们的代码。客户端 JavaScript 库,例如那些在 Dojo toolkit, Prototype, 和 Script.aculo.us 中提供的,包含了处理那些问题的特性。
难以调试。由于 AJAX 代码分配在客户端和服务端之间, JavaScript, DOM, CSS 等的多种类型代码的结合,调试 AJAX 代码会很困难。
需要开发者与 UI 问题做斗争。 AJAX web 应用引入了许多 UI 问题。例如,你怎样为一个 AJAX 网页支持书签,如果他的内容经常改变但 URL 不会。你怎样为一个页面的特定状态做书签。另外,你怎样支持后退按钮?另一个简单的应用,开发者必须考虑这些 UI 问题并编写处理它们的代码。客户端 JavaScript 库,例如那些在 Dojo toolkit, Prototype, 和 Script.aculo.us 中提供的,包含了处理那些问题的特性。
难以调试。由于 AJAX 代码分配在客户端和服务端之间, JavaScript, DOM, CSS 等的多种类型代码的结合,调试 AJAX 代码会很困难。
幸运的,新的调试工具例如
Mozilla Firebug
调试器正在出现,以使调试
AJAX
代码更加简单。
GWT
也提供调试客户端和服务端代码的环境。请看本文的
Design Strategy 6: Go All Java Technology
部分。
暴露
JavaScript
代码-一个潜在的安全问题。在
web
应用客户端上的的
JavaScript
代码是看的见的。包括黑客在内的任何人可以看见并分析浏览器页面上的源代码。危害会随之而来。他们可能试图相反的操纵你的
web
应用。他们甚至可以从你的
web
应用上劫持
XMLHttpRequests
并返回破坏性的响应。
设计策略
2
:使用客户端
JavaScript
库
无须为
AJAX
应用编写所有的客户端
JavaScript
代码,你可以利用
JavaScript
库的优势,他们提供
AJAX
功能,例如
: Dojo toolkit, Prototype, Script.aculo.us,
和
Rico
。要找其他的,请见
Survey of AJAX/JavaScript Libraries.
Dojo toolkit
是一个开源的
JavaScript
工具箱,它的库和
API
可以轻松的将
AJAX
置入
web
应用。例如,
dojo.io
库抽象化同服务端的
AJAX
通信,所以隐藏了底层的
XMLHttpRequest
操作。使用
XMLHttpRequest
库,
AJAX bookstore2
应用程序中的
bpui.alone.showPopupInternal()
函数将会变成这样:
dojo.require("dojo.io.*");
...
// This function is called after initial timeout that represents the delay
bpui.alone.showPopupInternal=function(popupx, bookId) {
// retrieve data through dojo call
var bindArgs = {
url: "../PopupServlet?bookId=" + escape(bookId),
mimetype: "text/xml",
load: bpui.alone.ajaxReturnFunction};
// dispatch the request
bpui.alone.req=dojo.io.bind(bindArgs);
dojo.require()
函数动态的为指定的库装载
JavaScript
代码,这里是
dojo.io
库。更新的
bpui.alone.showPopupInternal()
函数使用
dojo.io.bind()
方法向服务端提交一个异步的请求。
bind()
方法包装了
XMLHttpRequest,
因此你不必再像
do-it-yourself
方式那样创建和配置
XMLHttpRequest
对象。你需要为
bind()
方法提供以下参数:与之通话的服务端组件的
URL
,响应的格式,和回调函数标识。你也可以指定其他的参数,如
error
。
Dojo toolkit
中的其他库提供多种
API
,可以使编码变得简单,例如:动画,
DOM
操作,拖拽支持,
UI
效果。另外,工具箱提供完善的事件处理机制。尽管如此,
Dojo toolkit
由于他的内置窗口部件库而闻名,你可以预创建
UI
组件,然后将它插入
web
应用并根据需要定制它。
Dojo
窗口部件能让你创建自己的部件。
Prototype
是一个
JavaScript
框架。它提供一个库,库的构件包含能使
JavaScript
应用简易化的对象。其中一个构建提供一个
AJAX
对象,类似
Dojo toolkit
中的
dojo.io
库,封装了
XMLHttpRequest
对象并隐藏了
XMLHttpRequest
操作。另一个构件提供一些对象和方法可以使操作
DOM
更简单。
Script.aculo.us
和
Rico
是在
Prototype
的基础上建立的。二者都提供支持
AJAX
,拖拉,
UI
效果,和其他插入
web
应用功能的
JavaScript
库。
使用客户端
JavaScript
库的正面和反面
这里有一些使用客户端
JavaScript
库建立
AJAX web
应用的正面和反面。
正面
隐藏底层细节。
Dojo toolkit
中的
dojo.io
库、
Prototype
库,此类库都封装了
AJAX
的一些细节。包括创建和配置
XMLHttpRequest
对象,和在这些对象上执行的一些操作。这些库允许你在一个更高、更抽象的层次上编码,使你不必提供更多的细节代码。
减少
JavaScript
编码的需要。
Dojo toolkit DOM manipulation
或者
Prototype DOM manipulation
之类的库提供例行程序,可以方便的被使用并且比起他们的等价的
JavaScript
库需要更少的代码。另外,组装类似
Dojo toolkit
里预建的窗口部件要比编写
JavaScript
功能简单的多。
进行
AJAX
的时候处理浏览器的不兼容性。客户端
JavaScript
库类似
Dojo toolkit
中的那些,隐藏了很多不同浏览器处理
AJAX
的不同方法。例如,
dojo.io.bind()
方法请求封装了
XMLHttpRequest
,可以处理
IE
创建异步请求时的不同。
Prototype
为
DOM
操作提供的对象隐藏了浏览器处理
DOM
相关操作时的不同。另外,客户端
JavaScript
库包含了功能退化(
"graceful degradation"
)特性,以处理
AJAX
不能支持的情况-使你不必编写代码来应对那种可能性。
处理一些常见的
AJAX
问题,比如书签和后退按钮支持。众多的客户端
JavaScript
库提供书签和后退按钮的支持。例如,你可以通过将
dojo.io.bind()
的
changeURL
参数设为
true
就可以轻易的为
bookstore2
程序添加书签支持。
dojo.require("dojo.io.*");
...
// This function is called after initial timeout that represents the delay
bpui.alone.showPopupInternal=function(popupx, bookId) {
// retrieve data through dojo call
var bindArgs = {
url: "../PopupServlet?bookId=" + escape(bookId),
mimetype: "text/xml",
load: bpui.alone.ajaxReturnFunction};
changeURL:true;
// dispatch the request
bpui.alone.req=dojo.io.bind(bindArgs);
为这些工具设立的用户社区可以帮助回答疑问。类似
Dojo toolkit
的著名客户端库拥有著名的用户社区,通过基于社区的论坛和博客提供支持和帮助。另外,
Dojo
之类的开源库社区参与进行对库的扩展和增强。这包括公司的支持和贡献。例如,
Dojo
基金会,一个为促进使用
Dojo
和
JavaScript
而设立的非盈利性组织,获得了
IBM
和
Sun Microsystems
公司等的赞助和积极协助。
反面
需要一些
JavaScript
知识。客户端
JavaScript
库不能排除对
JavaScript
编码的需要。最多降低了编写
JavaScript
代码的需要。在更新的
bookstore2
例子里,使用
Dojo toolkit
排除了编码创建、配置和使用
XMLHttpRequest
对象的需要,但你同样要编码调用封装了
XMLHttpRequest
请求的
dojo.io.bind()
函数。
可能需要混合和匹配
JavaScript
库。这可以被看作优点和缺点。如果一个单独的
JavaScript
库不能给你所需的功能,你可以灵活的从其他的
JavaScript
库获得另外的功能,从同一个或这另一个工具箱里。不会限制你只能在
web
应用里使用一个客户端
JavaScript
库。例如,你可以使用
Prototype
对象来同服务端进行
AJAX
通信,使用
Dojo toolkit
里的窗口部件实现
UI
。灵活是一件好事。尽管如此,不同的客户端库来源有自己语法结构,所以你需要学习使用这些库的不同方法。
可能无法满足所有的
AJAX
需求。有这种可能性,客户端
JavaScript
库不会满足所有的将
AJAX
置入
web
应用的
JavaScript
需要。因此你需要另一种方法来满足其他的需求。
设计策略
3
:使用客户端框架
将
AJAX
置入
web
应用的另一种方法是使用客户端框架。有许多客户端框架供你使用,包括
JavaServer Faces
框架例如
Java EE 5 SDK, ICEfaces, Ajax4jsf,
和
Project Dynamic Faces
中的那些。同样有其他类型的客户端框架,例如
Direct Web Remoting (DWR),
和
the Google Web Toolkit (GWT)
,他们不是基于
JavaServer Faces
的。本节将讨论
JavaServer Faces
的使用。
Project Dynamic Faces -- a Variation on Adding AJAX to JavaServer Faces Technology Components
一节将讨论
Project Dynamic Faces
。
Design Strategy 5: Go Remote
讨论
DWR
,
Design Strategy 6: Go All Java Technology
一节讨论
GWT
。
JavaServer Faces
,经常被称为
JSF
,为简化建立丰富的
UI web
应用而设计。这个技术的核心是一个强大的组件模型。可以提供一系列
API
表现
UI
组件并管理它们的状态。这些
API
也为开发者提供编程处理组件的事件,转换和验证输入数据的方法。
JavaServer Faces UI
组件实际上是服务端的组件。它们在服务端运行并在客户端呈现,可以响应客户端的事件。
使用
JavaServer Faces
的好处之一是它允许页面作者可以在自己的页面上使用
UI
组件而不必知道组件工作的细节。典型的,这些组件在
JSP
页面上使用
JSP
标记-虽然这不是表现组件的唯一方式。对页面作者来说,在页面里包含
JavaServer Faces UI
组件与使用
JSP
标记一样简单。
JavaServer Faces
核心组件的
JSP
标记库被作为该技术的标准部分提供。
同样重要的,
JavaServer Faces UI
组件被设计为易于引入到集成开发环境(
IDE
)的,例如
Sun Java Studio Creator IDE.
这使开发者可以通过拖放可视控件来将
AJAX
置入
web
应用。
值得注意的,
JavaServer Faces
组件模型是可扩展的所以组件开发者可以创建定制的控件。这也意味着组件开发者可以创建带有
AJAX
功能的
JavaServer Faces
组件或者将
AJAX
功能加入已存在的组件。就如本文前面提到的,
AJAX JavaServer Faces
组件库(
library of AJAX-enabled custom JavaServer Faces components
)已经是
JAVA
设计方案手册(
Java Blueprints Solutions Catalog
)的一部分。
创建和使用包含
AJAX
功能的组件不会减少
AJAX
代码的数量。组件开发者同样需要提供
JavaScript
,
CSS
和
DOM
代码以实现
AJAX
功能,但是对页面作者来说可以遮蔽代码的细节。
你可以在设计手册上查到所有的
AJAX
的
JavaServer Faces
组件。让我们来看其中的一个:一个使用监听方式的
JavaServer Faces
组件。这个定制组件包含与
bookstore 2
程序中相似的功能。当用户鼠标移动到组件上方,将触发一个弹出气球的函数见图
3
。
你可以在
"Using PhaseListener Approach for Java Server Faces Technology with AJAX"
中找到这个组件的详细描述。状态监听器是一个接口
JavaServer Faces
请求处理的每一阶段都会收到通知。使用状态监听器只是处理
JavaServer Faces
请求的多种方式之一。例如,你可以使用
servlet
。请在设计手册上察看这些和其他的方法。
为在
JSP
页面使用定制组件,页面作者需要引用定制组件的
tag
库和标准
JavaServer Faces
库,并为页面里的组件指定标记。
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib prefix="ui" uri="http://java.sun.com/blueprints/ui" %>
...
<f:view>
<ui:compB id="pop1" url="faces/bpui_compb_action/CompBBean/processMethod?itemId="/>
</f:view>
<ui:compB>
是包含弹出气球功能的定制组件的标记。
url
参数包含服务端处理请求所需的信息。
JSP
页面同样包含将鼠标穿越事件映射到
JavaScript
函数的代码。
<a href="#" onmouseover="bpui.compB.showPopup('pop1', event, 'test1A')"
onmouseout="bpui.compB.hidePopup('pop1')" style="cursor: pointer">
<b>Mouse over link to see popup (test1A)</b></a><br/>
<small><i>(With a JSF Managed Bean fulfilling the AJAX Request)</i></small><br/><br/>
这基本上是页面作者需要的关于弹出气球的所有代码。
尽管如此,组件开发者仍需要提供鼠标穿越事件触发的
JavaScript
函数。跟往常一样,函数创建和配置
XMLHttpRequest
对象并用它提交异步请求。
bpui.compB.showPopupInternal=function(popupx, itemId) {
// initialize the AJAX request
bpui.compB.req=bpui.compB.initRequest();
// retrieve the correct popup object that is being shown
popObject=bpui.compB[popupx];
// concatenate the itemId value to the URI
url=popObject.urlx + escape(itemId);
// set the correct popup's callback function
bpui.compB.req.onreadystatechange = popObject.ajaxReturnFunction;
bpui.compB.req.open("GET", url, true);
// send the request
bpui.compB.req.send(null);
}
组件开发者必须为回调函数提供代码以更新页面的
DOM
表现。
this.ajaxReturnFunction=function() {
// make sure response is ready
if (bpui.compB.req.readyState == 4) {
// make sure it is a valid response
if (bpui.compB.req.status == 200) {
// populate the popup with the info from the response
var resultx=bpui.compB.req.responseXML.getElementsByTagName("response")[0];
document.getElementById(componentId + "_title").innerHTML=
resultx.getElementsByTagName("title")[0].childNodes[0].nodeValue;
document.getElementById(componentId + "_message").innerHTML=
resultx.getElementsByTagName("message")[0].childNodes[0].nodeValue;;
// show popup with the newly populated information
document.getElementById(componentId).style.visibility='visible';
} else if (bpui.compB.req.status == 204){
// error, just show alert
alert("204 returned from AJAX call");
}
}
}
此种途径与
do-it-yourself
途径的不同是它封装在服务端的定制控件里。定制组件呈现组件标记,如同
<script>
标记一样。标签指明了组件的
JavaScript
文件。当页面呈现定制组件的时候,会创建一个对定制标签指定的
URL
的调用。
URL
的第一部分,
faces
,被映射到一个
FacesServlet servlet
。注意,
JavaServer Faces
框架实现模型-视图-控制器(
MVC
)设计模式。
FacesServlet
是框架里的控制器。
FacesServlet
的映射由
web
应用的配置描述
web.xml
执行。
在
JavaServer Faces
请求处理生命周期期间,框架调用定制组件的状态监听器,它在组件的
faces-config.xml
配置描述里被注册。装填监听器检查
URL
,看是否请求与定制组件相关联。如果相关,状态监听器执行基于
URL
内容的请求。
如图
4
所示,页面呈现之后,用户发动一个鼠标越过事件,处理事件的
JavaScript
函数创建并配置一个
XMLHttpRequest
对象(
1
)并用它提交异步请求。多种服务器组件参与出了请求,包括
FacesServlet
和状态监听器(
2
),还要受管理的
bean
(
3
),它其中的方法创建一个
XML
响应。然后回调函数基于返回的
XML
更新
DOM
(
4
),生成并显示弹出气球(
5
)。
图
4
:使用状态监听器处理
AJAX
请求
使用
JavaServer Faces
的正面和反面
正面
也没作者不需要懂得
Javascript
,
CSS
,
DOM
。如上个例子所示,在页面上使用
AJAX
组件,页面作者只需要涉及定制组件的标记库,为组件指定标记,并将相关事件映射到
Javascript
函数。在这里例子中,页面作者同样需要指定组件标记的
URL
。这里面不需要页面作者懂得任何
Javascript
,
CSS,DOM
。
AJAX-enabled custom components are reusable. JavaServer Faces UI components are reusable. A page author can use them whenever and wherever they are needed. This is also true for AJAX-enabled components.
AJAX
定制组件可以被重复使用。
JavaServer Faces UI
组件是可以重复使用的。页面作者可以在他们需要的任何时候任何地方使用。
AJAX
组件也是同样的。
组件开发者可以利用
JavaServer Faces
的优势。
JavaServer Faces
提供丰富的处理事件和转换验证用户输入的体系结构。组件开发者可以充分利用这些包含
AJAX
功能的
UI
组件。
应用程序开发者可以通过拖放可视组件来将
AJAX
添入
web
应用。
JavaServer Faces UI
组件,包括定制组件,设计为易于被引入集成开发环境(
IDE
)的例如
Sun Java Studio Creator IDE.
实际上,一系列
AJAX JavaServer Faces
组件已被
Sun Java Studio Creator IDE
包装。如果
AJAX
的组件被引入到
IDE
,应用开发者可以简单的通过拖放组件到应用程序视图来实现添加。
反面
有许多和
do-it-yourself
同样的缺点。使用
JavaServer Faces
并不能消除
do-it-yourself
开发者面对的一些问题。组件开发者仍需要编写
Javascript
代码-潜在的有很多,并懂得处理
CSS
和
DOM
的复杂工作方式。组件开发者同样需要与浏览器的不兼容性,后退按钮和书签之类的
UI
问题做斗争。尽管如此,一个叫做
Dynamic Faces
的项目处理了一些这样的问题。
Dynamic Faces
使添加
AJAX
功能到
JavaServer Faces UI
组件变得更简单。
Project Dynamic Faces
-将
AJAX
添加到
JavaServer Faces
组件过程的升级。
使用
Dynamic Faces
的主要的优势是降低了你将
AJAX
动能添加到组件所需要写的代码量。实际上,使用
Dynamic Faces
可以完全消除
JavaScript
代码的需要。例如,设想一个页面含有菜单选项,两个按钮,和一个输出文本域。你想要
AJAX
化组件,文本域需依赖于用户的选择异步更新,不是整个页面的刷新。因此,页面作者需在页面上指定
Dynamic Faces
标记库并设置组件的
AJAX
区。
<%@ taglib prefix="jsfExt"
uri="http://java.sun.com/jsf/extensions/dynafaces" %>
<jsfExt:ajaxZone id="selectzone"
action="#{updateOutput}">
<h:commandButton id="Selection1" ...
actionListener=.../>
<h:commandButton id="Selection2" ...
actionListener=.../>
<h:outputText value= .../>
<h:selectOneMenu .../>
</jsfExt:ajaxZone>
在指定
AJAX
区标签里指定组件告诉
Dynamic Faces
哪个
JavaServer Faces
组件需要使用
AJAX
。
注意这里不需要
JavaScript
代码。特别的,这里不需要创建,配置和操作
XMLHttpRequest
对象,或者提供服务端处理
AJAX
请求的任何代码。
Dynamic Faces
处理设计
AJAX
请求的所有底层细节。当用户点击两个按钮中的任一个,他将会调用
#{updateOutput}
动作。这是很简单的
JavaServer Faces
编码而不需要任何
JavaScript
。
Dynamic Faces
使编码一对多
AJAX
请求变得简单,一个组件的事件异步的更新许多其他的
AJAX
组件。
Dynamic Faces
允许你用一个
AJAX
请求这样做。如果不用
Dynamic Faces
,你需要为每个组件发出分离的
AJAX
请求,一些人称之为“游泳航线”(
"swim lane"
)方法。
Dynamic Faces
同样提供
JavaScript
库,你可以在组件之外用来精密控制。例如,你可以在
AJAX
区使用
Dynamic Faces JavaScript
库连接事件与某些组件,然后连接另一事件与其他
AJAX
组件。
最后,由于
Dynamic Faces
建立于
JavaServer Faces
框架,你仍然可以利用框架的所有优势,例如输入验证,转换,和状态管理。
设计策略
4
:包装
客户端
JavaScript
库和客户端框架提供不同的优势。但是有没有将二者结合的方法,使
JavaScript
库在客户端框架内可用。回答使肯定的。达到此种目的的一种努力是开源的
jMaki
项目。
jMaki
(发音
jay-MAH-kee
)是一个框架,用来将
JavaScript
部件包装进
JSP
标记或
JavaServer Faces
组件。名字
jMaki
聪明地加入
Java
-这就是
jMaki
中
j
代表的意义-包装-
Maki
是日语包装的意思。
jMaki
提供一个包装组件库,它们来自多种流行
JavaScript
库例如
Dojo toolkit
和
Script.aculo.us
。超过
30
种的
jMaki
部件已经可用。你可以在
jMaki Widget Gallery
里查看这些组件。
jMaki
框架同样提供添加一系列
jMaki
部件的方法。
页面作者在页面里包含
jMaki
部件同
JSP
标记、
JavaServer Faces
组件一样。例如,有一个
jMaki
的标记是一个来
Dojo
部件库的内联编辑器部件。这里有页面作者如何像包含
JavaServer Faces
组件一样包含部件的方法:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib prefix="a" uri="http://java.sun.com/jmaki-jsf" %>
...
<f:view>
<a:ajax name="dojo.inlineedit"/>
</f:view>
注意,
jMaki
标记库引入就在
JavaServer Faces
标记库引入的后面。
jMaki
包含两种标记库-一种是
JSP
标记另一种是
JavaServer Faces
组件。作为页面上标记的响应,
jMaki
为部件生成适当的
JavaScript
代码-还有
HTML
和
CSS
。
需要
3
个文件定义一个
jMaki
部件:一个
HTML
模版文件,指定了部件的页面版式,一个
CSS
文件,指定部件的样式参数,一个
JavaScript
文件,指定部件的行为。为将一个部件添加到一组
jMaki
部件里,你需要提供部件的
3
个文件。例如,这是内联编辑器部件的
JavaScript
文件
:
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.InlineEditBox");
dojo.require("dojo.event.*");
dojo.widget.createWidget(widget.uuid);
var editable = dojo.widget.byId(widget.uuid);
editable.onSave = function() {
var id = widget.uuid;
alert("saving " + id);
};
jmaki.attributes.put(widget.uuid, editable);
JavaScript
代码为部件引入
Dojo
库,并包括一个
JavaScript
函数的调用,创建一个部件的实例。
你可以使用
jMaki
包装一个
JavaScript
库里的部件-是一个类似
Dojo
或者
Prototype
客户
JavaScript
库中的部件,而不是
jMaki
里已提供的部件-或者创建自己的部件并包装它。当然,如果你创建自己的部件你必须编写完全指定它行为的
JavaScript
代码。如果行为包含
AJAX
功能,你必须编写代码实现那些功能。这包括创建和配置
XMLHttpRequest
对象以创建异步请求,并编写一个回调函数。
使用
jMaki
的正面与反面
正面
隐藏
JavaScript
细节。因为
jMaki
封装类似
Dojo
等
JavaScript
库的部件,它提供使用这些部件的所有优势,例如隐藏
AJAX
底层细节,处理浏览器的不兼容性,并处理类似书签的
UI
问题。你可以使用一个或多个
JavaScript
库中的这些部件而不必了解每个库的不同语法。
jMaik
为开发者提供了一致的语法,而不管部件的来源是什么。当然你也不必编写部件里已经提供了的
JavaScript
代码。
此外,由于
jMaki
使部件像
JSP
标记和
JavaServer Faces
组件一样可用,它也提供了
JSP
和
JavaServer Faces
的优势。页面作者不需要懂得
JavaScript
,
CSS
和
DOM
。页面作者可以简单的通过将
jMaki
标记库引入然后指定部件的标记的方式来在页面上包含部件。由于部件包装的像
JavaServer Faces
组件一样,开发者可以利用
JavaServer Faces
处理事件的体系的优势,转换验证用户输入。在
Sun Java Studio Creator IDE
和
NetBeans IDE
之类的应用开发环境中,应用开发者同样可以通过拖放方式使用包装部件。在
NetBeans IDE 5.5 Beta
里可以获得一个
jMaki
插件模块。
集成到
Project Phobos
脚本框架。不仅可以与
JSP
和
JavaServer Faces
协作,
jMaki
也可以与
Project Phobos
脚本框架协作。
Phobos
是一个专注于建立一个用脚本语言创建
web
应用的框架的项目。框架同样允许开发者使用
Java
语言而不使用脚本语言,来执行任务。
jMaki
到
Project Phobos
的集成允许开发者在框架中使用
jMaki
部件。
反面
需要一些
JavaScript
的知识。除非你使用已封装到
jMaki
的部件,不然你仍需要知道一些
JavaScript
知识。如上一例子所示,如果你使用
jMaki
包装
JavaScript
库中的部件,你需要编写代码为部件引入适当的包,并调用
JavaScript
函数创建部件实例。如果你创建自己的部件,你不惜编写
JavaScript
代码以指定它的行为,和
CSS
指定它的样式。如果行为包含
AJAX
功能,你必须编写
JavaScript
代码实现该功能-包含
DOM
操作。
设计策略
5
:远程调用
使用
AJAX
的另一种途径是使用远程框架,例如
Direct Web Remoting (DWR)
和
JSON-RPC
。这些框架是开发者可以通过远程过程调用(
RPC
)-就像
JavaScript
调用来将
AJAX
置入应用程序。例如,返回本文先前讨论的弹出式气球。你可以为弹出气球在服务端创建一个简单的类来处理
AJAX
请求。你可以把类叫做
Popup
,把类中提供书籍细节的方法叫做
getDetails.
在客户端,你编写一个
JavaScript
函数,这个函数在鼠标越过事件时触发。在
JavaScript
代码里调用
getDetails
方法:
<script type="text/javascript" src="dwr/engine.js"></script>
<script type="text/javascript" src="dwr/util.js"></script>
<script type="text/javascript">
...
showPopupInternal=function(popupx, bookId) {
Popup.getDetails(bookId, ajaxReturnFunction)
}
...
该方法的参数,
ajaxReturnFunction
,是一个回调函数。你必须在客户端编写回调函数。尽管如此,你不必编写创建、配置
XMLHttpRequest
对象的底层细节。
DWR
框架为你做了这些。框架在客户端生成一个远程方法调用(
RMI
)
stub
的等价物。
Stub
是一个包括
XMLHttpRequest
底层操作的类
.
然后框架处理生成的
JavaScript
类与服务端之间的交互数据。这包括转换客户端
JavaScript
传递的参数,和转换服务端
Java
返回的值。在服务端,框架生成一个叫做
DWRServlet
的
servlet
,接收请求并将它分配给
Popup
类处理。
注意在代码开头部分确定的两个
DWR JavaScript
库文件。
dwr/util.js
文件包含一个可以用来更新
web
页面的
JavaScript
库。例如,你可以使用有用的函数
$(id)
来替代等价的
DOM API document.getElementById(id)
访问和处理
DOM
中的元素。
dwr/engine.js
文件包含了处理客户端
stub
与服务端调用的功能。
使用
DWR
的正面与反面
正面
隐藏底层
AJAX
细节。你可以通过对服务端
Java
方法的类似
RMI
的函数调用方式来创建一个
AJAX
请求。
DWR
框架处理了底层的细节,例如创建和配置
XMLHttpRequest
对象并在这些对象上执行操作。
需要
Java
开发者使用熟悉的方法结构来创建
AJAX
请求。
DWR
调用的类似
RMI
的语法结构对大多数
Java
应用开发者来说很熟悉。
允许开发者通过很小的努力将现有的业务逻辑暴露给
AJAX
客户端。如果你在服务端有业务逻辑可以处理
AJAX
请求,你就可以通过一个简单的方法调用从客户端
JavaScript
函数访问那个逻辑。
提供安全控制。
DWR
提供多种控制保护远程类和方法免遭暴露。远程类只有在被在配置文件
dwr.xml
中指定的情况下,才能通过
DWR
被暴露。这些控制可以更精确的暴露远程类中仅被指定的方法。
DWR
同样支持
Java
平台,
Java EE
基于角色的权限控制。允许的
Java EE
角色拥有指定远程类或方法的权限。
反面
需要
JavaScript
知识。虽然
DWR
框架生成
AJAX
通信的底层细节代码,你仍然需要编写事件触发的
JavaScript
代码-例如鼠标越过或点击事件。同样需要编写回调函数的代码。但你可以通过使用
DWR
连同
jMaki
部件,
AJAX
的
JavaServer Faces
组件,或其他封装
JavaScript
的组件来降低代码的数量。
只对
Java
对象起作用。
DWR
专门为
JavaScript
客户端和服务端
Java
对象设计。比较起来,不同的
JSON-RPC
实现存在不同的语言。
设计策略
6
:所有
Java
技术
JavaServer Faces
和
jMaki
是使用
Java
建立
AJAX
应用的途径。但是它们仍需要开发者写一些
JavaScript
代码。尽管如此,有一些仅
Java
的途径。其中之一是使用
Google Web Toolkit (GWT). GWT
是免费的-虽然不开源-客户端框架,需要开发者专门使用
Java
语言建立
AJAX
应用。这包括应用客户端-
GWT Java-to-JavaScript
编译器将
Java
语言转换成
JavaScript
代码和
HTML
。在服务端,你可以服务端
Java
技术的优势,例如
servlets, JSP,
和
JavaServer Faces
。
////////
使用
GWT
为
AJAX
应用建立
UI
与在
Java Foundation Classes/Swing (JFC/Swing)
等
UI
框架中建立
UI
相似。在被称为面板的虚拟容器中,你可以通过布置一系列
GWT UI
部件来安排用户接口。这就像在
JPanel
等容器中通过放置
UI
组件来布置
JFC/Swing
应用的
UI
一样。
GWT
提供一个经常使用部件的库。你可以创建组合多种
GWT
部件的合成部件,或者创建你自己的部件。
GWT
的事件模型延续了
JFC/Swing
模式。为使用响应事件的部件,你需要实现一个
GWT
监听接口。然后你调用事件的监听方法,传递部件的类型参数。例如,下面这个例子显示两个按钮,并当用户点击其中一个的时候调用
onClick
方法。
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.clinet.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FlowPanel;
public class ListenerExample extends Composite implements ClickListener {
private FlowPanel fp = new FlowPanel();
private Button b1 = new Button("Button 1");
private Button b2 = new Button("Button 2");
public ListenerExample(){
setWidget(fp);
fp.add(b1);
fp.add(b2);
b1.addClickListener(this);
b2.addClickListener(this);
}
public void onClick(Widget sender) {
if (sender == b1) {
//b1 click handler
...
else (sender == b2) {
//b2 click handler
...
}
}
}
使用
GWT
的正面和反面
正面
需要开发者使用
Java
语言建立
AJAX
应用。开发者不需要懂得
JavaScript, CSS,
或
DOM
。
GWT Java-to-JavaScript
编译器将客户端
Java
代码编译为
JavaScript
代码和
HTML
。
提供
GWT
主机模式,这是一个能够执行调试的环境。你可以在主机模式运行你的
AJAX
应用程序。这允许你使用你的
IDE
调试设备测试和调试程序。
处理浏览器的不兼容性。
GWT Java-to-JavaScript
编译器生成适应浏览器的
JavaScript
代码,节省开发者为浏览器的不兼容性编程。
由
Google
开发和支持。这意味着
Google
提供了有关使用
GWT
的良好文档和社区资源。
反面
生成的
JavaScript
代码有缺陷。虽然使用
GWT
不需要懂得
JavaScript
,你有时可能需要检查生成的
JavaScript
代码-例如,如果浏览器显示了一个
JavaScript
错误。对于不熟悉
JavaScript
的开发者,理解
GWT
生成的
JavaScript
代码可能有困难。也因为
GWT
生成
JavaScript
代码,你失去了对处理的精密控制。
其他信息
关于作者
Ed Ort
是
java.sun.com
的专职成员。他写作范围广阔,涉及关系型数据库,编程语言,和
web
服务。
Mark Basler
是一位高级软件工程师,
Java
蓝图团队成员,协助创建
Java Blueprints Solution Catalog
和
Java Pet Store Demo 2.0
,另外还有一些展示如何设计和开发
AJAX WEB 2.0
的相关应用程序。它的其他贡献包括设计和开发
SUN
下载中心的关键组件,电子商务套件,和
Sun Java
系统应用服务器。