AJAX设计策略(全)

 
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 代码会很困难。
幸运的,新的调试工具例如 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 代码,你失去了对处理的精密控制。
 
其他信息
·       Hands-On Java EE 5
·       JSF Extensions
·       Project jMaki
·       Direct Web Remoting
·       Java Pet Store Demo 2.0
·       Java EE Technologies
·       Java EE SDK
关于作者
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 系统应用服务器。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值