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应用。相反的,客户端基于响应来更新页面。这意味着,只有部分页面被更新。换句话说,网页像一个模版一样被处理:客户端和服务端交换数据,客户端基于收到的数据来更新模版的某部分。可以这样认为,使用AJAXweb应用受事件和数据的驱动,而传统的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应用使用HTMLXHTML类的标记语言来呈现页面,或者JSP类服务端技术来生成网页。另外,服务端应用系统在AJAX应用中扮演一个关键的角色。类似Java EE的服务端应用系统包括对关于AJAX的数据验证,用户身份管理,和持久性配置的很好支持。请看本文的AJAX and Server-Side Java Technologies部分。

 

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技术,同时也是客户端技术例如JavaScriptXML,都是关于客户端和服务端交互数据的。事实上XMLHttpRequest对象向服务端创建的请求是一个HTTP请求。对服务端来说,处理AJAX请求和处理传统web应用的HTTP请求没有不同-任何服务端技术都可以处理请求,包括Java EE的服务端java技术例如servletsJSP技术,和JavaServer Faces技术。事实上,Java EE非常适合AJAX方法。JavaServer Faces和包含支持数据验证,用户身份管理,持久性的其他Java EE技术,非常适合于AJAX

例如,你可以用servlet处理请求,管理客户端状态,访问企业资源,并为响应生成XML。或者你可以创建定制的JavaServer Faces组件进行服务端处理,也可以封装处理客户端的JavascriptCSS

设计策略

作为开发者,你有很多个将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 TutorialDuke's Bookstore例子的其中一个。你可以在Java EE 5 TutorialThe Example JSP Pages部分找到创建bookstore2 web应用的说明。

最初的bookstore2web 表列了可以购买的书籍。用户和现在的bookstore2应用和交互是一个传统的同步交互。用户点击列表里书的标题进一步察看这本书的更多信息。这需要服务端完成所有的页面刷新。

这个发标在文章"Creating an AJAX-Enabled Bookstore Application"的例子添加了一些AJAX功能,是web应用能够弹出气球。添加的功能提供了更多的动态UI。当用户将鼠标越过表列的书目,关于书的细节将出现在弹出气球上,如图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库,封装了一些类似创建和配置XMLHttpObjectAJAX操作,它们将减少你所需要编写的代码。如果库可以提供你需要的AJAX功能,使用它会比编码实现功能简单很多。请查阅本文的Design Strategy 2: Use a Client-Side JavaScript Technology Library部分。
需要若干种语言和技术的知识。AJAX代码需要你懂得JavaScriptCSS,和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创建异步请求时的不同。PrototypeDOM操作提供的对象隐藏了浏览器处理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 FacesDesign Strategy 5: Go Remote 讨论 DWRDesign 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代码的数量。组件开发者同样需要提供JavaScriptCSSDOM代码以实现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),还要受管理的bean3),它其中的方法创建一个XML响应。然后回调函数基于返回的XML更新DOM4),生成并显示弹出气球(5)。

 

4:使用状态监听器处理AJAX请求

使用JavaServer Faces的正面和反面

正面

也没作者不需要懂得JavascriptCSSDOM。如上个例子所示,在页面上使用AJAX组件,页面作者只需要涉及定制组件的标记库,为组件指定标记,并将相关事件映射到Javascript函数。在这里例子中,页面作者同样需要指定组件标记的URL。这里面不需要页面作者懂得任何JavascriptCSS,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代码-潜在的有很多,并懂得处理CSSDOM的复杂工作方式。组件开发者同样需要与浏览器的不兼容性,后退按钮和书签之类的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-这就是jMakij代表的意义-包装-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代码-还有HTMLCSS

需要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封装类似DojoJavaScript库的部件,它提供使用这些部件的所有优势,例如隐藏AJAX底层细节,处理浏览器的不兼容性,并处理类似书签的UI问题。你可以使用一个或多个JavaScript库中的这些部件而不必了解每个库的不同语法。jMaik为开发者提供了一致的语法,而不管部件的来源是什么。当然你也不必编写部件里已经提供了的JavaScript代码。

此外,由于jMaki使部件像JSP标记和JavaServer Faces组件一样可用,它也提供了JSPJavaServer Faces的优势。页面作者不需要懂得JavaScriptCSSDOM。页面作者可以简单的通过将jMaki标记库引入然后指定部件的标记的方式来在页面上包含部件。由于部件包装的像JavaServer Faces组件一样,开发者可以利用JavaServer Faces处理事件的体系的优势,转换验证用户输入。在Sun Java Studio Creator IDE NetBeans IDE之类的应用开发环境中,应用开发者同样可以通过拖放方式使用包装部件。在NetBeans IDE 5.5 Beta里可以获得一个jMaki插件模块。

集成到Project Phobos脚本框架。不仅可以与JSPJavaServer Faces协作,jMaki也可以与Project Phobos脚本框架协作。Phobos是一个专注于建立一个用脚本语言创建web应用的框架的项目。框架同样允许开发者使用Java语言而不使用脚本语言,来执行任务。jMakiProject 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框架为你做了这些。框架在客户端生成一个远程方法调用(RMIstub的等价物。Stub是一个包括 XMLHttpRequest底层操作的类. 然后框架处理生成的JavaScript类与服务端之间的交互数据。这包括转换客户端JavaScript传递的参数,和转换服务端Java返回的值。在服务端,框架生成一个叫做DWRServletservlet,接收请求并将它分配给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部件,AJAXJavaServer Faces组件,或其他封装JavaScript的组件来降低代码的数量。

只对Java对象起作用。DWR专门为JavaScript客户端和服务端Java对象设计。比较起来,不同的JSON-RPC实现存在不同的语言。

设计策略6:所有Java技术

JavaServer FacesjMaki是使用Java建立AJAX应用的途径。但是它们仍需要开发者写一些JavaScript代码。尽管如此,有一些仅Java的途径。其中之一是使用Google Web Toolkit (GWT). GWT是免费的-虽然不开源-客户端框架,需要开发者专门使用Java语言建立AJAX应用。这包括应用客户端-GWT Java-to-JavaScript编译器将Java语言转换成JavaScript代码和HTML。在服务端,你可以服务端Java技术的优势,例如servlets, JSP, JavaServer Faces////////

使用GWTAJAX应用建立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, DOMGWT 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代码,你失去了对处理的精密控制。

其他信息
原文地址:https://www.cnblogs.com/godwar/p/808223.html