• 个人日志首页
  • 全部日志
  • 我的相册
  • 心情日记
  • 爱情
  • 我的QQ签名
  • 给我留言
  • 在本站搜索
  • 当前位置个人日志>>学习笔记
  • 推荐: 最短的黄色小说 | 2007感动中国十大人物

ajax-整合的力量

  • 本文转载(原文):http://www.blogjava.net/eamoi/archive/2006/12/18/88606.html

    一整合的力量

    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 的主要功能及其所带来的便捷。

    2.3 循序渐近

    从 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 文档内容。 

    2-1.jpg

     

    图 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-2.jpg

    图 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 效果。

     

    2-3.gif

    图 3 Dojo 所实现的标签面板

     

    2-3.jpg

     

    图 4 Dojo 所实现的仿 Windows 窗口

     

    3.3 循序渐近

    从 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) ,

           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 功能函数来改变网页内容。

    2-4.jpg

     

    图 5   DWR 交互过程

     

    DWR 是作为 Web 应用程序中的 servlet 部署的。把它看作一个黑盒子,这个 servlet 有两个主要作用:首先,对于公开的每个类, DWR 动态地生成包含在 Web 页面中的 Javascript 。生成的 Javascript 包含存根函数,代表 Java 类上的对应方法并在幕后执行 XMLHttpRequest 。这些请求被发送给 DWR ,这时它的第二个作用就是把请求翻译成服务器端 Java 对象上的方法调用并把方法的返回值放在 servlet 响应中发送回客户端,编码成 Javascript 。 DWR 还提供了帮助执行常见的用户界面任务的 Javascript 工具函数。

    4.3 循序渐近

    有两种方式可以开始 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 开发包。将这个开发包放到 \WEB-INF\lib 目录下。如果使用 DWR1.1 ,则下载的应该是 DWR1.1 的开发包。这个开发包中包含了 DWR 运行所需的全部 Java 类及相应的 API 。 dwr1.0.jar 也可以从随书光盘 software 目录中找到。

    第二步:修改 web.xml ,添加 Servlet 映射

    修改 \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 来处理。