添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Oracle Account

Manage your account and access personalized content. Sign up for an Oracle Account

Sign in to Cloud

Access your cloud dashboard, manage orders, and more. Sign up for a free trial

BEA WORKSHOP 中的 AJAX 编程

作者:Gary Horen
03/05/2008

以客户机为中心的Ajax编程工具

开发人员需要的这组Ajax工具主要由所选编程模型控制。有关这个主题的讨论,请参见我以前的文章 探索Ajax运行时服务。由于以客户机为中心的运行时(如Dojo)主要是一个JavaScript API库,所以开发人员至少需要一个JavaScript编辑器和调试器。

通常,以客户为中心的运行时完全独立于服务器端技术,开发人员需要选择在它们之间传递的异步(即,Ajax)消息的格式。对于这种编程模型非常重要的另一个工具是消息检查工具,它能够显示在Ajax页面生命期任意时刻客户端与服务器间的交换顺序。

本文将阐述如何在BEA Workshop中安装和使用Aptana, Inc.提供的免费的JavaScript编辑器和调试器,还将概述如何在Firefox扩展Firebug插件中使用消息检查工具。读者会很清楚地看到,这些工具包都提供了良好的特性,但此主题不在本文的讨论范围之内。我希望本文能够促使您去进一步研究它们。

示例应用程序

示例应用程序是一个简单的数据网格。单击Load table from按钮,程序将检索从 http://dev2dev.bea.com/2008/03/SakiData.json 返回的 JSON 格式的数据流(此过程不会刷新页面),它将用于加载空的数据网格。该标记的介绍请参见JSON简介。

此版本的示例应用程序拥有一个向其提供可用数据的方法:JSON编码的静态文件。在本文结束部分,您会找到一个可供下载的Workshop项目,它提供了静态数据文件和.jsp动态生成的流,展示了相同数据可以在服务器端Java对象之外怎样轻松地串行化。在这段代码中,我使用一个名称为 XStream ,的开源库,最初该库设计用于串行化Java对象到XML,其最新发布的版本包含了一个特性,将使用同样的API产生一个JSON流。它使许多针对串行化到JSON问题的备选开源解决方案之一。

数据网格功能和浏览器与服务器之间的异步管道由 Dojo Toolkit 提供,它使一个免费的开源Ajax运行时。

查看示例应用程序

安装工具

本文将演示来源不同的两款工具:Firebug,按照 这些 指令可以将它安装到当前版本的Firefox中; Aptana JavaScript工具,使用位于http://update.aptana.com/install/3.2/的更新站点提供的Eclipse Update Manager(Help→Software Updates→Find以及Install...)可以将它安装到BEA Workshop 10.1(或任何Eclipse 3.2实例)中。本文还讨论了免费的版本(Community Edition);Aptana提供了Professional Edition升级,它提供了更酷的特性,如JSON Editor、Firefox和Internet Explorer中的调试以及商业支持。Community Edition只支持Firefox中的调试。

XHR流量检查工具

Firebug XHR检查工具是一个很好的工具,它将在当前Web页上显示Ajax(XMLHttpRequest)交互纪录。如果您正使用安装了Firebug插件的Firefox阅读本文,那么您可以通过Tools菜单打开Firebug(Tools→Firebug→Open Firebug——在新窗口中)。单击Net标签,接着单击XHR,然后单击按钮在上述的应用程序弹出窗口中装载数据表。

图2显示JSON流的服务器请求记录。如果您打开请求并单击Response标签,Firebug将显示提供给浏览器的JSON流(见图3)。马上,我们会在调试器中看到数据如何被装载到数据网格部件中。

XHR message history
图2. XHR消息记录

JSON response to XHR request
图3. XHR请求的JSON响应

JavaScript调试

现在来看Aptana编辑器/调试器。Firebug提供了一个调试工具,实际上,Aptana调试器就依赖于Firebug的底层机制。使用Aptana工具的优势是能够在同一个窗口中使用Eclipse UI进行编辑和调试,这正好符合您所习惯的方式(在使用Java的时候,能够在Eclipse的这些任务之间实现无缝的来回切换)。

我将使用部署在WebLogic Server上的BEA Workshop项目演示调试器(下面提供了下载方法),因为使用您开发的与服务器端代码结合的调试器将很可能是最普通的用例。您还需要进行一点特殊的设置,使调试器理解WTP动态Web项目的结构,并且我将讨论一些最佳实践供您借鉴,确保这些工具与您的应用程序代码很好地合作。

通过上述安装的Aptana工具,下载 DojoWebProject.zip 并引入一个使用BEA Workshop 10.1的工作区。(使用Project Import向导,File→Import... General→Existing Projects into Workspace,然后单击Select Archive File radio按钮。)此项目包括本文的文本、Dojo Toolkit 1.0.2、Saki_table.html中的单独Ajax应用程序、SakiData.json中的静态JSON流和展示如何动态提供同一数据的SakiData.jsp。它们应该部署到Workshop 10.1 BEA Home目录下的WebLogic Server 10.0(在本文中,我选择使用wlserver_10.0/samples/domains/workshop_10.1域)。

重要提示 :由于许多Dojo代码未通过各种IDE验证,因此您应该打开项目的服务器定义并选中 Ignore project compilation errors when publishing (见图4)以确保虚假验证错误不会阻碍部署。

Ignore project compilation errors when publishing
图4. 在发布时忽略项目编译错误

编写

让我们来看一下JavaScript和JSP代码是如何构成的。图5显示了一个单独的Web页面。请注意,除dojo.require()调用之外,JSP页面中没有任何JavaScript代码,它们都在一个单独的文件(项目中的Saki_table.js)中。这是因为:由于服务器会将JSP文件编译到一个Java类中,然后该类将在浏览器中显示HTML,所以在JSP页面源文件中指定的行号与显示的HTML中的同一行没有直接联系。由于JavaScript调试器对Java EE不无所知,所以它不理解这种失配,因此不能发现运行的JavaScript代码中的断点——如果它们是根据JSP源指定的话。

解决这种分离的方法是将所有需要调试的JavaScript保存在.js文件中,必须由浏览器(即,使用<script>标签)而不是JSP编译器解析引用。(使用<%@ include file="path" %>或<jsp:include page="path"/>将JavaScript代码引入一个JSP页面会令您处于同样的情形,类似于将代码放入了JSP源中:在显示页面之前,后两个方法包含JavaScript,而第一个方法将在显示页之后是浏览器向服务器请求它。)

需要注意,熟悉XML的JavaScript编程新手通常会遇到这样一个陷阱:<script>标签必须使用</script>关闭,决不能用<script src="mumble..."/>。使用后者会导致Dojo加载失败,Web页面将会出现不可预料的混乱情况。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
        <title>Saki Table</title>
        <meta http-equiv="Content-Type" CONTENT="text/html;charset=utf-8"></meta>
        <style type="text/css">
                @import "dojo-release-1.0.2/dojox/grid/_grid/Grid.css";
                body {
                        font-size: 0.9em;
                        font-family: Geneva, Arial, Helvetica, sans-serif;
                .heading {
                        font-weight: bold;
                        padding-bottom: 0.25em;
                #grid {
                        border: 1px solid #333;
                        width: 35em;
                        height: 30em;
        </style>
        <script type="text/javascript" src="dojo-release-1.0.2/dojo/dojo.js" djConfig="isDebug:false, parseOnLoad: true"></script>
        <script type="text/javascript">
                dojo.require("dojox.grid.Grid");
                dojo.require("dojox.grid._data.model");
                dojo.require("dojo.parser");
        </script>
                               <script type="text/javascript" src="Saki_table.js"></script>
</head>
<div class="heading">Sample Dojo application: loads JSON data into dojox.grid.Grid</div>
<input type="button" value="Load table from" onclick="populateTable();" />
<input id= "targetURL" type="text" size=60 value="http://localhost:7001/DojoWebProject/SakiData.json"/>
<div id="grid" dojoType="dojox.Grid" model="model" structure="layout"></div>
</body>
</html>
                            
图5. Saki_table.jsp

图6显示了我们在Saki_table.js文件中定义的JavaScript。

 // Initial setup (runs when page loads)                
 // data grid layout: 
 // a grid view is a group of columns
 var view1 = {
        cells: [[
      {name: 'Character', width: "150px"}, 
      {name: 'Appears in Saki story', width: "300px"}
 // a grid layout is an array of views.
 var layout = [ view1 ];
 // the model will contain the data to be displayed in the view
 // This model object is connected when the grid is defined 
 // (see Saki_table.html).   It contains no data until the request 
 // is issued to the server in populateTable().
 model = new dojox.grid.data.Table(null, null);
 // Process the response to the asynchronous request
 function handleResponse(serverDataStream, ioArgs)
        var unmarshaledData = eval("(" + serverDataStream + ")");
        if (unmarshaledData.response.type == "data") {                                  // normal response
                model.setData(unmarshaledData.response.tableContents);          // populate the model object with data; grid will display
                alert(unmarshaledData.response.message);          // application-detected error
 function handleError()
        // system-detected error
 // Issue an asynchronous request to the server for data.
 function populateTable()
        var targetURL = dojo.byId("targetURL").value;   // get URL entered by user
     dojo.xhrGet({
         url: targetURL,
         load: handleResponse,
         error: handleError
图6. Saki_table.js

在启动调试器之前,我们先快速查看一下.js文件(图6所示):

  • 当.js文件被加载到页面中的时,将调用函数外部的代码;通过初始设置,它将定义几个页面范围的JavaScript变量。无论将文件引入HTML页还是一个JSP,该代码都将以同样的方式工作;下面的Workshop项目包含这二者。
  • populateTable()方法包含在输入框输入的URL并通过Dojo向服务器提交一个异步请求以得到数据。它指定handleResponse()方法作为回调,当服务器相应到达时,Dojo将调用它。
  • 当从服务器返回数据流时,handleResponse()将调用内置的JavaScript函数eval()。eval()将JSON解组为JavaScript对象树,其结构可以在下面的调试器Variable视图看到。


配置和使用调试器

调试之前,需要将项目部署到WebLogic Server。我建议在服务器上使用Run As→Run进行浏览器端调试部署;根据我的经验,如果同时有两个活动的调试会话(例如,一个JSP和一个 JavaScript会话,或者一个Java调试会话和一个 JavaScript会话),则Eclipse框架有时会变得相当混乱。

Web应用程序部署后,IDE将调出Debug对话,选择Web Browser→Firefox配置调试器。

WTP动态Web项目默认开发人员的Web文件位于project-root/WebContent目录,还可以在HTTP请求中提交的URL中省略它。Aptana调试器的默认配置没有这样的假设;它不知道WTP项目的结构。因此,您必须在调试器配置中指定一个到文件夹URL的映射以便指示调试器如何进行解释。在Debug对话中,如图7所示,映射Server路径省略了WebContent目录。

Mapping Web Server Paths
图7. 映射Web Server路径

然后,在Debug对话的Main标签中使用服务器的基地址并选中 Append project name (见图8)配置调试器会话启动一个特定的页(您可以在项目中浏览它)。

Debugger launch settings
图8. Debugger启动设置

此时,可以启动调试器,它将调出一个Firefox实例,Aptana调试器扩展已经加载到该实例中。然后,我们将在Saki_table.js中的handleResponse()函数的第一行设置一个断点。

当断点触发时(图9),您可以看到Debug标签中的调用堆栈和Variables标签中的变量树。Variables视图打开之后,便可检查unmarshaledData.response.tableContents中包含的字符串嵌套数组,它即将被传递到Grid数据模型。

Workbench window in Debugger perspective
图9. Debugger透视图中的Workbench窗口2010-3-26

请注意该方法中的调试器声明。有时调试器会与浏览器失去同步,并且不会触发编辑器UI中设置的断点。当出现这种情况时,通常最简单的应急之策是在文件中放入一段调试器声明,在它被解释的时候触发断点。自此,变量查看和指令步进工作良好。

结束语

这是一篇简短但详尽的介绍,这些工具可以结合BEA Workshop助力以客户为中心的Ajax开发。这两种工具还包含许多其他特性,留待读者进一步研究。

JavaScript调试器与运行时框架自身一样并非绝对完美。在调试器中未能触发断点仍然是一个不断出现的问题——在网上搜索“missing breakpoint Firebug”便可了解。根据我的经验,这通常是Firebug层的问题(Aptana调试器依赖这个层,该层本身又依赖浏览器的JavaScript实现)。在代码中置入一段调试器声明一般都能够解决这一问题。工具有这些缺陷并不意味着它们就不是Ajax程序员工作台的一个重要部分。它们是从调用到alert()和控制台写入的一个很大的提高,就像他们对于Java和C编程那样。我们依然还处在真正的、普遍的JavaScript开发的早期。这些工具将不断得以改善。

参考资料

产品:

Gary Horen 是BEA Workshop小组的Ajax and Languages 项目经理。

false ,,,,,,,,,,,,,,,,