异步 JavaScript 和 XML (Ajax) 是使用本机浏览器技术构建富 Web 应用程序的新方法。对于编写需要某些类型的“活动”用户界面的复杂应用程序的开发人员,JavaScript 在这方面已经做得很好。不过,JavaScript 难于编码、调试、移植和维护。使用 Ajax 工具包有助于最大程度地减少使用 JavaScript 和 Ajax 带来的许多常见问题。优秀的 Ajax 工具包提供了一组可重用的小部件、用于扩展和创建小部件的框架、事件系统、JavaScript 实用工具和增强的异步服务器调用支持。在本文中,我们将讨论如何使用 Dojo 工具包为 Java EE 应用程序构建企业 SOA 客户端。我们还将使用 JSON (JavaScript Object Notation)–RPC 来调用服务器端 Java 对象。
在本文中,我们还将向您提供以下内容的简要说明:Ajax、Dojo、JSON 和 JSON-RPC,以及一些设计 Ajax 应用程序的设计原则和您可以下载并亲自尝试运行的简短示例。
有许多关于 Ajax 的论文、文章和书籍。我不打算对 Ajax 进行深入介绍。有关详细信息,请查阅参考资料。
Ajax 可作为使用本机浏览器组件构建网站的体系结构样式。Ajax 的关键部分有:
- JavaScript,它可以编排页面元素,从而获得最佳 Ajax 用户体验。
- Cascading Style Sheets (CSS),它可以定义页面元素的可视样式。
- 文档对象模型(Document Object Model,DOM),它将网页结构作为一组可以使用 JavaScript 操作的可编程对象提供。
- XMLHttpRequest,它支持以后台活动的形式从 Web 资源检索数据。
XMLHttpRequest 对象是关键部分。
XMLHttpRequest 对象是 Ajax 用于进行异步请求的机制。图 1 说明了该流程:
图 1. XMLHttpRequest 对象进行异步请求的流程图
XMLHttpRequest 对象是浏览器中提供的 JavaScript 对象。(Microsoft™ 和 Mozilla 浏览器各有自已的版本)。该流程如下所示:
- 页面调用某个 JavaScript。
- JavaScript 函数创建 XMLHttpRequest 对象。这包括设置要调用的 URL 和 HTTP 请求参数。
- JavaScript 函数注册回调处理程序。HTTP 响应调用此回调处理程序。
- JavaScript 函数调用
XMLHttpRequest
对象上的send
方法,该方法接着将 HTTP 请求发送到服务器。 XMLHttpRequest
对象立即将控制返回到 JavaScript 方法。此时,用户可以继续使用该页面。- 稍后,HTTP 服务器通过调用回调处理程序返回 HTTP 响应。
- 回调处理程序可以访问 HTML DOM 对象。它可以动态更新页面元素,而无需中断用户(除非您碰巧更新用户正在使用的 DOM 对象)。
通过异步更新页面的 DOM,还可以在本地进行异步请求。
Dojo 使您能够方便地构建动态站点。它提供一个丰富的小部件库,您可以使用它组成页面。您可以使用基于 Dojo 方面的事件系统将事件附加到组件,以创建丰富的交互体验。此外,您可以使用几个 Dojo 库进行异步服务器请求、添加动画效果和浏览存储实用工具等等。
Dojo 提供了您可以用于构建页面的一组丰富的小部件。您可以使用多个方法创建 Dojo 小部件。Dojo 的众多优点之一是它允许您使用标准的 HTML 标记。然后,可以将这些标记用于小部件。这样,HTML 开发人员就可以方便地使用 Dojo,如清单 1 所示:
清单 1. 在 HTML 标记中使用 Dojo
|
您可以使用 div
标记来定义小部件的位置,而在页面加载或对事件进行响应时 Dojo 可以在这些地方放置小部件。您还可以使用更具体的标记,如 <dojo:widget>
,并向其中添加 Dojo 小部件属性。在清单 1 中,我们将 dojoType
属性添加到 button
标记。在设置了标记之后,您需要在一些 JavaScript 内部加载小部件,如清单 2 所示。您可以将标记嵌入到页面内部,但是我们建议将其放置在单独的 JS 文件中。在本文的稍后部分中,我们将阐明一些 MVC 设计原则。
清单 2. 在 HTML 标记中使用 Dojo
|
您可以在 JavaScript 中创建、访问、修改和删除小部件,从而实现动态行为。在我们的示例中,您将看到在 JavaScript 中访问小部件的示例。
Dojo 事件系统使用面向方面的技术将事件附加到小部件。这可以将小部件与实际的事件处理分离。Dojo 不是将硬代码 JavaScript 事件添加到 html
标记上,而是提供允许您将事件附加到小部件的 API,如清单 3 所示。
清单 3. 使用 Dojo 将事件处理程序附加到小部件
|
通过使用 connect
方法,您可将 JavaScript 方法连接到小部件。您还可以在 div
节点上附加 dojoAttachEvent
,如下所示。某些 HTML 标记没有定义事件,所以这是一个方便的扩展。
清单 4. 使用 Dojo 将事件附加到 HTML 标记
|
Dojo 事件系统还允许多个高级功能,如:
- 声明在现有的事件处理程序之前或之后插入事件处理程序的建议。
- 允许小部件在浏览器中订阅或发布主题。
- 添加事件回调。
- 可用于表示事件的
event
规范化对象。
有关详细信息,请参见 http://dojo.jot.com/EventExamples。
Dojo 通过抽象特定于浏览器的详细信息,提供了对服务器进行异步请求的简单方法。Dojo 允许您创建数据结构来隐藏详细信息,如清单 5 所示。
清单 5. 使用 Dojo 进行异步请求
|
此外,Dojo 使用 JSON-RPC 标准支持 RPC。在接下来的部分中,我们将看一看 Dojo 对 JSON 的支持。
Dojo 是一个具有许多功能的丰富库,包括:
- 处理 html、字符串、样式、dom、正则表达式和若干其他实用工具的通用库。
- 包括字典、ArraryLists、队列、SortedList、设置和堆栈的数据结构。
- 用于添加动画效果、验证、拖放和若干其他功能的可视化 Web 实用工具。
- 数学和加密库。
- 存储组件。
- XML 解析
有关详细信息,请参见 http://manual.dojotoolkit.org/index.html。
JSON 是 JavaScript 的对象文字符号的子集,它是在 JavaScript 中表示数据结构的常用方法。JSON 是一种完全与语言无关的文本格式,但使用编程人员熟悉的与 C 语言家族(包括 C、C++、C#、Java、JavaScript、Perl、Python 和许多其他语言)类似的约定。这些属性使 JSON 成为 Ajax 客户端的理想数据交换语言。
JSON 构建在两种结构的基础上:
- 名称/值对的集合。在不同的语言中,它被实现为对象、记录、结构、字典、哈希表、有键列表或者关联数组。
- 值的有序列表。在大多数语言中,它被实现为数组、向量、列表或序列。
JSON 对象的示例如下:
|
在示例中,我们对值对进行了命名。括号中的任何内容都是一个列表。在不同的编程语言中都有一组丰富的实现。有关详细信息,请参见 http://json.org/。
JSON-RPC 是一种轻量级远程过程调用协议,在此协议中,JSON 可以连续请求和响应。向远程服务发送请求可以调用远程方法。该请求是具有三个属性的单个对象:
method
- 包含要调用的方法名称的字符串。params
- 作为参数传递到方法的对象数组。id
- 请求 ID。它可以属于任何类型。它用于将响应与其应答的请求相匹配。
当方法调用完成时,服务必须对响应进行应答。此响应是具有三个属性的单个对象:
result
- 被调用方法返回的对象。它必须为null
,以避免在调用该方法时发生错误。error
-error
对象(如果在调用方法时发生错误)。它必须为null
(如果不存在任何错误)。id
- 它必须是与响应的请求相同的 ID。
通知是没有响应的特殊请求。它与带有一个异常的请求对象具有相同的属性:
id
- 必须为null
。
XML 是一种用于面向服务的体系结构 (SOA) 和数据传输的常见传输。当然,目前许多服务以 SOAP 格式存在。不过,何时将其用于数据传输在 Ajax 社区中存在分岐。JSON 有以下几个优点:
- 浏览器解析 JSON 的速度比 XML 快。
- JSON 构造是友好的编程语言,并容易转换为后端编程语言(如 Java)。
- JSON 相当稳定。JSON 的附加内容将成为超集。
XML 有以下优点:
- 调用将 XML 用作传输的现有服务。
- 使用 XSLT 可以动态转换 XML。这是企业服务总线 (ESB) 方案中的理想功能。
Dojo 为调用 JSON-RPC 请求提供了抽象层。用于 Dojo 的 JSON-RPC 引入了标准方法描述(Standard Method Description,SMD)的概念。SMD 文件是 JSON-RPC 服务的描述。它允许您以中立方式描述 JSON 调用。清单 6 提供了此类 JSON 调用的示例:
清单 6. Dojo 中的 SON 调用
|
您可以使用 Dojo API 调用服务:
var StockService = new dojo.rpc.JsonService("/path/to/StockService.smd"); StockService.getStockData("IBM",stockResultCallback);
这将通过网络发送此结构:
{"id": 2, "method": "getStockData", "params": ["IBM"]}
JSON-RPC 为远程过程调用定义标准格式,但是不存在对后端技术的标准映射。JSON-RPC Java Orb 提供了这样一种机制:注册 Java 对象,并将它们公开为 JSON-PRC 服务。它还在 JavaScript 中提供客户端 API,以调用服务。
如果您选择使用 Dojo,则可以编写自已的绑定代码。用于 Java 的 JSON API 可以提供帮助。有关详细信息,请参见 (http://developer.berlios.de/projects/jsontools/)。在我们的示例中,我们将使用 JSON-RPC Java ORB 进行异步请求,以利用服务器端绑定代码。
JSON-RPC Java Orb 允许您在一种 Servlet 范围(请求、会话、应用程序)内注册 Java 对象。然后,它可以使用 JSON-RPC 请求来调用 Java 对象。为此,可以将对象类型放在 JSON 对象之前。由于 Dojo API 不执行此操作,所以用于 JSON-RPC 的 Dojo 客户端 API 与用于 Java 的 JSON-RPC 不兼容。
清单 7 提供了如何向 HttpSession 注册 Java 对象的示例:
清单 7. 注册 Java 对象的 HttpSession
|
您可以在 Servlet 或 HttpListener 中执行此操作。然后将 JavaScript 客户端写入到 Java 服务,如清单 8 所示。
清单 8. 连接 Java 服务的 JSONRpcClient
|
此请求会发送以下有效负载:
{"id": 2, "method": "StockService.getStockData", "params": ["IBM"]}
响应与以下所示类似:
{"result":{"javaClass":"com.ibm.issw.json.service.StockData","price":100, "companyName":"International Business Machine","symbol":"IBM"},"id":2}
用于 Java 客户端的 JSON-RPC 将处理此响应,并向您提供一个静态接口。
为了支持请求,您需要注册特殊的 Servlet。稍后,我将向您介绍如何执行此操作。
JSON-RPC Java ORB 的一个缺点是只有单个 URL,这导致使用 Java EE 安全来保护 URL 非常困难。作为一种变通方法,您可以在 HTTP 会话层注册服务,并根据安全需要添加它们。
在此部分中,我将讨论一些设计原则,然后详细讲解一个示例。您可以下载完整的 WAR 文件,并亲自尝试该应用程序。
在 Java EE 领域中,模型-视图-控制器 (MVC) 已经变得非常成熟,这归功于 Struts 和 JavaServer Faces 之类的框架。使用 Ajax 可以进行正确的 MVC 设计,这对成功的 Web 应用程序至关重要。此外,SOA 允许直接从 Ajax 应用程序调用服务。这样做有几个优点,如 WebSphere 期刊文章 "AJAX Requests – Data or Markup?" 中所述。
图 2 提供了 Ajax 客户端和 Java EE 应用程序之间理想生态系统的简要概述。
图 2. Ajax 客户端和 Java EE 应用程序之间的理想生态系统
在服务器端,业务和门户功能现在被公开为某一类型的服务接口。在服务的形式下,应遵循正确的服务器端最佳实践。服务器应用程序应公开过程粒度服务。JavaServer Faces 之类的框架现在负责执行初始呈现;不过,对于客户端 Ajax 工具包,这是可选的。
在浏览器上,分离关注的内容非常重要。图 3 突出显示了 Java 服务器文件结构:
图 3. Java 服务器文件结构
您可以选择每页有一个 JavaScript 控制器。不过,对于复杂的门户页,您可以将相关事件分组成小型的控制器集。
控制器文件应:
- 向小部件加载网络请求处理程序,如图 4 所示:
图 4. 将请求处理程序附加到小部件
- 实现请求处理程序。请求处理程序不应有太多的逻辑。它们应委派给服务 Facade,以便与后端交互。
- 实现回调处理程序方法。回调应将呈现委派给独立 JS 文件。此外,它们应将存储中间状态的工作委派给独立 Java 服务器文件。对于无状态交互,可以直接将结果传递到 rendering.js 文件。
图 5 说明了组件之间的流:
图 5. 从客户端到请求处理程序,再到回调处理程序的信息流
呈现文件包含呈现组件的逻辑或基于事件结果的用户界面。
Business Facades 应包含代理服务器请求的方法。DataCopy 应维护需要本地保存在浏览器中的本地视图对象。
对于 Dojo,您必须添加 JavaScript 文件作为 Web 应用程序的一部分。您可以将 dojo 文件夹复制到 Web 应用程序文件夹,如图 6 所示:
图 6. 添加使用 Dojo 所必需的 JavaScript 文件
为 JSON-RPC Java Orb 设置 Java EE 应用程序
为了在应用程序中使用 JSON-RPC Java Orb,您需要在 Web 应用程序的 lib 目录中添加 json-rpc-1.0.jar。还需要将单个 jsonrpc.js 文件添加到 Web 内容文件夹中,如图 7 所示:
图 7. 添加使用 JSON-RPC Java Orb 所必需的 JavaScript 文件
为了使 Java EE 应用程序能够接收用于 Java 请求的 JSON-RPC,您必须添加 JSONRPCServlet,如清单 9 所示:
清单 9. 使用 JSONRPCServlet 所需的代码
|
Ajax 使 SOA 客户端更完美。在我们的示例中,我们使用了一个简单的 Java 服务。
图 8 是基于 Java 的服务模型:
图 8. 基于 Java 的服务模型
我们使用了一个简单的硬编码实现,如清单 10 所示:
清单 10. 简单的硬编码 Java 服务
|
使用 JSON-RPC 公开 Java 服务
为了公开 Java 应用程序,我使用了被称为 ExportServices 的 HttpSessionListener,以便为用户注册服务,如清单 11 所示:
清单 11. ExportServices,即公开 Java 服务的 HttpSessionListener
|
您需要将侦听器添加到应用程序中(通过将其添加到 web.xml),如清单 12 所示:
清单 12. 添加到 web.xml 的 ExportServices 侦听器
|
设置了基础结构并公开了服务之后,现在我们可以构建 Web 客户端了。通过 Dojo,我们利用小部件构建网页并利用事件模型。图 9 说明了建议的开发过程:
图 9. 开发过程示例
我将使用此过程演示该示例。
从小部件构建 UI
首先构建 UI。请参见清单 13,了解示例 UI。
创建 UI:
- 加载脚本:
- dojo
- jsonrpc
- StockClientController
- resultRenderer
- 构建页面,并结合使用
div
和 HTML 标记以创建 Dojo 小部件。
清单 13. HTML UI
<html> <head> <title>Stock Form</title> <script type="text/javascript" src="../dojoAjax/dojo.js"></script> <script type="text/javascript" src="../jsonrpc.js"></script> <script type="text/javascript" src="../view/resultRender.js"></script> <script type="text/javascript" src="../controller/StockClientController.js"></script> <link REL=StyleSheet HREF="../StockApp.css" TYPE="text/css" ></link> </head> <body> <div class="layout" dojoType="LayoutContainer"> <div dojoType="ContentPane" class="stockContent" layoutAlign="bottom" id="docpane" isContainer="true" executeScripts="true"> <div dojoType="FloatingPane" class="stockPane" title="Stock Form" id="pane" constrainToContainer="true" displayMaximizeAction="true"> <h2>Stock Service</h2> Enter symbol: <input dojoType="ValidationTextBox" required="true" id="stockInput"> <p /> <button dojoType="Button2" widgetId="stockButton"> Get Stock Data </button> <div id="resultArea" /> </div> </div> </div> </body> </html>
- StockClientController.js 非常关键。在脚本的开头,使用
dojo.require
方法加载所需的小部件,然后初始化 Dojo 环境,如清单 14 所示。
清单 14. 初始化 Dojo 环境的 StockClientController
//require statements dojo.require("dojo.widget.*" ); dojo.require("dojo.event.*"); dojo.require("dojo.widget.Button2"); dojo.require("dojo.widget.FloatingPane" ); //all dojo.require above this line dojo.hostenv.writeIncludes(); dojo.require();
操作前后需要考虑的事项
在 Ajax 中,需要考虑的一件事是,在触发事件之前,不要显示某些用户界面。不过,一种做法是放置 div
标记作为占位符。然后,可以使用 DOM 或 Dojo API 访问此区域,并添加动态 UI 元素。在我们的应用程序中,我添加了一个简单的 div
,以获得以下结果:
<div id="resultArea" />
附加样式表
接下来,使用 CSS 添加样式。CSS 是设置 Ajax 应用程序格式的标准方法。使用 CSS,您可以将样式定义应用于多个 div
标记,方法是将标记的 class
属性设置为该样式的名称。这允许您重用样式定义。清单 15 显示了我使用的样式表:
清单 15. 在 UI 中使用的样式表
|
服务视图
接下来,一个好的想法是确保 UI 开发人员在 JavaScript 中拥有一个服务视图。Dojo 使用 SMD 来做到这一点,如前面所述。用于 Java 的 JSON-RPC 为我们提供了直接从 JavaScript 调用 Java 服务的能力,如清单 16 所示:
清单 16. 直接调用 Java 服务的 JavaScript
|
构建请求事件处理程序
接着,在控制器 JS 文件中,我们需要创建事件处理程序和回调处理程序。回调处理程序应是其他工作的 Facade。在我们的示例中,事件处理程序将异步调用我们的服务,并将回调传递到相应的方法。XMLHttpRequest
对象的此抽象由 JSON-RPC-Java 提供。在接收到响应时,回调委派给呈现,如清单 17 所示:
清单 17. 控制器文件中的回调和事件处理程序
|
在加载时加载初始 UI 和网络请求事件
下面,我们在页面初始化时使用 Dojo 这种有力的工具,将小部件连接到请求处理程序。请参见清单 18 中的 init
方法。dojo.addOnLoad()
方法允许您使用同一面向方面的技术,将 init
方法附加到页面加载事件。
清单 18. init() 方法
|
呈现响应
最后一步是添加动态呈现响应代码。我将它放置在独立呈现器 JS 文件中。您可以使用各种方法来呈现响应。在我们的示例中,我们将结合使用 DOM API 和 Dojo 实用工具来构建简单的表。在这里,我们可以使用 Dojo 的小部件之一,但是我希望对清单 19 中的函数 renderStockResult
使用自已的代码,以便突出显示一些 Dojo 实用工具和数据结构。
要创建呈现响应代码,请执行下列操作:
- 在
renderStockResult
函数中,使用dojo.byId()
方法访问resultArea
对象。 - 检查任何异常;如果
renderStockResult
含有传递给它的异常,它会将该异常传递到错误处理程序并返回。 - 使用
Dictionary
(类似于 JavaHashMap
)和ArrayList
Dojo 结构来存放result
数据。 - 将结构化数据传递到通用表创建者方法。
清单 19. 呈现响应方法
|
设置了数据结构之后,调用具体的 createTableWithVerticleHeading
方法。实际上,此类实用工具将会被外部化。在下面显示的方法中,我们将使用 Dojo Iterator
对象来遍历这些数据结构并创建表。我要在下面指出的另一个方法是 dojo.fx.html.fadeShow(table, 200)
,您可以使用该方法将淡入效果添加到结果的打印中。这只是某些动画的一瞬。在清单 20 中,Dojo 代码为粗体。
清单 20. 表创建方法
|
最后,我们将添加简单的错误处理方法,以打印错误消息,如清单 21 所示。请记住,通过在元素上设置类属性,然后委派给 CSS 文件,可添加粗体文本。
清单 21. 错误处理方法
|
测试应用程序
您可以下载应用程序的最终 WAR 文件。可将其安装在任何应用服务器(如 WebSphere Application Server)上。部署了应用程序后,您可以打开 HTML 页,以查看浮点形式,如图 10 所示:
图 10. HTML 中的浮点形式
可以自由移动该形式。您可能注意到,我已将浮点绑定到外部容器,如图 11 所示:
图 11. 绑定到外部容器的浮点
输入 IBM
以调用 Java EE 应用程序。结果应类似于图 12 所示的形式:
图 12. 将 IBM 输入到应用程序的结果
接下来,输入一些其他数据,以测试错误处理程序,如图 13 所示。
图 13. 测试错误处理程序
Dojo 还提供了单元测试套件以自动执行单元测试。
在本文中,我向您介绍了如何使用 Dojo 工具包、JSON 和 JSON-RPC 为 Java EE 应用程序构建 Ajax 客户端。我概述了每项技术,并介绍了一些设计原则。最后,我提供了一个示例应用程序。Ajax 应用程序将很快成为 SOA 客户端。通过使用 Dojo 之类的工具包,您可以方便地构建这些网页。
非常感谢 Chris Mitchell 审阅了这篇文章并提出了宝贵的意见。
描述 | 名字 | 大小 | 下载方法 |
---|---|---|---|
Sample code for this article | DojoJ2EE.war | 1.8MB | FTP|HTTP |
关于下载方法的信息 | Get Adobe® Reader® |
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
- developerWorks中国站点 Ajax 技术资源中心
- Ajax Hacks
- Ajax in Action
- developerWorks SOA and Web services 专区:获取有关 IBM 的 SOA 和 Web 服务的技术信息和资源。
- developerWorks WebSphere 与 SOA、Web Services 专栏:获取有关 IBM 的 SOA 和 Web 服务的技术信息和资源。
获得产品和技术
- Ajax Requests: Data or Markup(如果您没有使用 JSON-RPC,可以使用此库来执行转换。)
- Dojo
- JSON
- JSON-RPC
- JSON-RPC Java ORB
- JSON for Java(如果您没有使用 JSON-RPC,可以使用此库来执行转换。)
- 使用 IBM 试用软件构建下一个开发项目,这些软件可直接从 developerWorks 下载获得。
讨论
- 参与 developerWorks 博客,从而参加到 developerWorks 社区中来。
Roland Barcia 是位于纽约/新泽西州 Metro 区 IBM WebSphere 软件服务部 的 IT 咨询专家。他是 IBM WebSphere: Deployment and Advanced Configuration 的合著者。有关 Roland 的详细信息,请访问他的网站。 |