本文假设您已经下载了 Project Zero M4,并使用它创建过一个或多个应用程序。您需要对 Groovy 脚本编制、Ajax 技术和 HTML 有基本的理解,这些内容可以通过 Zero 的教程和示例获得。要获得关于 Project Zero 和相关技术的初级读物,请参阅 参考资料小节中的链接。
Google Charts 是一个非常出色的服务,它让开发人员可以使用简单的 HTTP GET 请求来生成图形和图表。客户机发送请求到 http://chart.apis.google.com/chart,同时发送的还有一个或多个查询参数,表明需要的图表的类型;这些查询参数的完整列表可在 Google Charts API 文档中找到(参见 参考资料)。目前,该 API 允许对很多属性进行控制,包括图表的标题、布局、颜色、轴线、数据和说明。
如果在图像上单击右键并选择 Properties,就可以看到用于生成该图表的 URL。在后面的小节中我将谈到查询字符串参数的具体作用。但是,查询参数的名称相当老套,在将它们组合到一个 URL 时,得到的 URL 冗长繁琐。在下一节中,您将开始使用 Project Zero 上运行的 Groovy 代码来封装这些复杂的 URL。
能够在浏览器中仅仅通过地址栏创建图表当然很好,但是正如 简介小节中所述,这样做实际上是很繁琐的。能够在地址栏中创建图表,对于非开发人员来说这看上去很有用,但是一旦稍微复杂一些,URL 就会显得太长。更好的设计方法是使用 HTTP POST 和 JSON(用于开发人员)公开图表的创建,并在此基础上提供图形化的界面(用于非开发人员)。这将使这两种用户都更容易地调试图表布局或数据方面的问题。可以使用 Project Zero 实现这种方法,具体做法是将图表 URL 的创建封装在一个 Groovy 脚本中,然后创建一个基于 Ajax 的 Web 界面,该界面通过 HTTP 调用那个脚本。
为了展示您的工作,您需要创建两个项目:一个存放
Groovy 包装器代码,另一个用于存放示例 Ajax UI。您应该创建两个
Zero 应用程序 —一个名为 zero.charts,另一个名为 chart.maker
—以分别存放 Groovy 代码和 Ajax 代码。这两个项目是分离的,以便允许不同的应用程序重用 Groovy 代码。您将从 zero.charts应用程序中开始。
使用 Groovy 简化图表创建的第一步是定义用于指定图表细节的数据结构。您不会使用 Google Charts 所用的原始参数名称,而是用 JSON 定义一个更详细的数据结构;使用 JSON 意味着可以依赖标准数据类型(例如实际的整数数组,而不是包含以逗号分隔的串行化的整数字符串),并且更容易看到什么值被传递给图表生成器。清单 1 展示了 Ajax 客户机与 Groovy 脚本之间的通信将使用的数据结构。
清单 1. 使用 JSON 的示例图表定义
{
title: "Sales for 1H 2008",
type: "bvg",
height: 300,
width: 300,
data: [34, 21, 28, 19, 48, 40],
xaxis: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
yaxis: [0, 40]
}
|
在开发期间,可以使用 FireBug 或简单的 JavaScript 警告等工具检查清单 1 中所示的 JSON 对象。与 http://chart.apis.google.com/chart?cht=bvg&chs=500x600&chtt=Sales%20for%201Q%202008&chd=t:134,219,188&chxt=x,y&chxl=0:|Jan|Feb|Mar|1:||300 这样冗长的字符串相比,这样的结构更容易调试和验证。
当然,归根到底,您仍然需要发送这样一个 URL 到 Google 的服务器,以获得所需的图表。为此,您将编写一个简单的 Groovy 方法,该方法将 JSON 对象中的字段值复制到一个图表 URL 中。借助 Groovy 的 GString 类型,您可以使 URL 字符串只有一行,而不必创建一个 java.lang.StringBuilder并逐个添加值。这个 Groovy 方法的代码如清单 2 所示。
清单 2. 构造图表 URL 的 Groovy 代码
def create(chart)
{
return "http://chart.apis.google.com/chart?chxt=x,y" +
"&cht=${chart.type}&chs=${chart.width}x${chart.height}" +
"&chtt=${chart.title}&chd=t:${chart.data.join(',')}" +
"&chxl=0:|${chart.xaxis.join('|')}|1:|${chart.yaxis.join('|')}";
}
|
基本上,清单 2 中的代码直接从 JSON 对象获得值并(使用 $语法)将这些值嵌入到 URL 中。惟一不同的是当 JSON 字段为数组时的情况,在此情况下,必须将它们的值连接成一个字符串。使用 join()方法很容易做到这一点。
您应该将清单 2 中的代码复制到一个名为
/zero.charts/app/scripts/charts.groovy 的文件中。通过将该代码放到 /app/scripts
目录中,可以让应用程序中的其他 Groovy 脚本以及在依赖关系列表中包括 zero.charts 的任何应用程序访问到它。使该代码易于重用的最后一步是为之创建一个 Groovy 绑定,这将使开发人员可以直接在代码中调用 create()方法,而不必使用 Zero 的更通用的
invokeMethod()
。要添加 Groovy 绑定,将清单 3 中的 Java™类定义复制到 /zero.charts/java 目录中。如果之前没有提供这个绑定,那么开发人员 必须输入 粗体显示的代码行。
清单 3. charts.groovy 的 Groovy 绑定
package zero.charts;
import java.io.FileNotFoundException;
import java.util.Map;
import org.codehaus.groovy.runtime.MethodClosure;
import zero.core.groovysupport.bindings.InvokeBindings;
public class ChartsBindings extends InvokeBindings
{
public void addVariables(Map<String, Object> variables)
{
super.addVariables(variables);
variables.put("create", new MethodClosure(this, "create"));
}
public Object create(Map<String, Object> chart)
throws FileNotFoundException, NoSuchMethodException
{
return invokeMethod("charts.groovy", "create", new Object[]{ chart });
}
}
|
在继续之前,注意传递给清单 3 中 create()的参数类型为 java.util.Map。在 Zero 中,JSON 对象和 Maps是一样的。Zero 的所有 I/O API 都知道如何在适当的时候完成 Map与 JSON 之间的串行化,所以您不必学习专门的 API 就可以直接操纵 JSON 对象。
一旦清单 3 中的 Java 类就绪,就必须将其注册到配置文件中,以便让 Zero 知道它的存在。清单 4 中的文本必须添加到 /zero.charts/config/zero.config 中,以确保 Groovy 绑定有效,并且对 create()的调用能够得到适当的处理。
清单 4. Groovy 绑定的配置
/config/bindings/.groovy += ["zero.charts.ChartsBindings"]
|
现在,您有了 URL 构造代码,接下来只需使用一个 RESTful API 来公开它。为此,您将创建一个名为 charts的 RESTful 资源类型,并使用 HTTP POST 方法接受图表规范(使用 JSON)并返回图表 URL。这个行为与 RESTful 应用程序中通常实现的行为稍微有些不同。通常,HTTP POST 会导致代码的执行,该代码在与请求 URI 相同的域中创建一个资源,并返回那个新资源的 URI。您将通过构造一个指向 Google Charts 服务的 URI 来 “创建” 一个资源,当客户机访问那个 URI 时,将得到图表。因此,您的服务真正创建并返回的惟一的内容就是一个图表 URI,该 URI 位于 HTTP 响应的 Location报头中。
清单 5 展示了 charts资源的 Groovy 代码。它的惟一的 HTTP 方法是 POST,该方法是在 onCreate()方法中实现的。您应该将该代码复制到一个名为 /zero.charts/app/resources/charts.groovy 的文件中。
清单 5. 用于图表创建的 REST API
import zero.json.Json;
/**
*
* @success 201 Returns the URI for the desired chart in the Location header.
* @error 500 The chart definition in the request body was not valid JSON.
* @format application/json
*
*/
def onCreate()
{
def chart = Json.decode(request.input[]);
def chartImageURL = create(chart);
request.headers.out.Location = chartImageURL;
request.status = 201;
}
|
在谈论用户界面之前,我们花点时间使用 RESTdoc 测试界面对 REST API 进行测试。启动 zero.charts 应用程序(zero run),并在 Web 浏览器中访问 http://localhost:8080/resources/docs/charts。您将看到,charts资源有一个方法(POST),如果单击它,将看到一个测试表单(如图 2 所示)。将 JSON 数据从 清单 1复制到请求体中,并单击 Send。您看到的响应应该包括一个 Location头,其中有一个 Google Charts URI。
图 2. 用于图表创建的 RESTdoc 测试表单
REST API 就绪后,现在可以在应用程序中使用它。下一节将展示如何使用 Ajax 创建可视化的图表构建器。
REST API 可以让开发人员更易于生成图表,它并不是用来帮助 99% 的不用编写代码的计算机用户的,而是针对那些偶尔为他们的文档和演示创建图表的用户。对于这些用户,可以使用一个 HTML 表单、一点 JavaScript 和最简单的 Ajax API XMLHttpRequest,创建一个简单的基于 Web 的图表构建器。图 3 展示了最终结果:Web 页面的一侧允许用户输入图表描述,而另一侧则显示生成的图表。
图 3. 用于生成图表的 Web 界面
要开始创建该用户界面,首先必须创建 chart.maker 应用程序与 zero.charts 应用程序之间的一个依赖关系。可以通过将 zero:zero.charts 添加到 /chart.maker/config/ivy.xml 实现。接下来的两个小节将展示最重要的 markup 部分以及界面所需的代码。通过下载本文包含的 示例项目,并查看 chart.maker 项目,可以看到完整的 markup 和代码。
如图 3 所示,用于获取用户图表的表单非常简单。除了一个输入值外,该表单上的所有东西都可以很轻松地转换为所需的 JSON 格式。惟一需要额外步骤的输入是图表类型,它是由 Google Charts API 使用两个或三个字母的缩写表示的。该表单显示对图表类型(Line Graph、Bar Chart - Vertical和 Bar Chart - Horizontal)的完整描述,因此 HTML 下拉菜单需要在这些描述与缩写(分别为 lc、bvg和 bhg)之间映射。清单 6 展示了所需 HTML 下拉菜单的定义。您可以看到用 粗体表示的图表类型代码。所有其他表单输入都是简单的文本框(<input type="text"/>)
清单 6. 用于图表类型的 HTML 下拉菜单
<select id="chartType">
<option value="lc">Line Graph</option>
<option value="bvg">Bar Graph - Vertical</option>
<option value="bhg">Bar Graph - Horizontal</option>
</select>
|
除了下拉菜单 markup 外,对于那些不熟悉这种控件的用户,还提供了从菜单中获取所选值的代码。与简单的文本框不同,不能直接读取该控件的 value属性 —必须遍历下拉菜单的选项,直到发现当前选中的项(selected)。清单 7 包含了实现这一功能所需的代码。
清单 7. 发现选中的图表类型的 JavaScript
function getSelection(elementName)
{
var select = document.getElementById(elementName);
for (var i = 0; i < select.options.length; i++)
if (select.options[i].selected)
return select.options[i].value;
return null;
}
|
另一个重要的 UI 元素是表单底部的 Create It!按钮。这个按钮并非用于提交表单,而是链接到一个 JavaScript 函数,该函数发出一个对 REST API 的 Ajax 请求。为此,需要将一个 JavaScript 函数调用添加到该按钮的 onClick事件中。清单 8 展示了链接到 createChart()函数的按钮单击事件,您将在下一节中实现该函数。
清单 8. 使用 JavaScript 初始化图表创建
<input type="button" value="Create It!" onClick="createChart();"/>
|
最后要详细谈到的 UI 元素就是显示所生成图表的图像。清单 9 展示了如何编写一个当页面装载时会隐藏的 HTML <img/>标记。您将使用 JavaScript 将该标记的源设为所生成图表的 URL,然后使之可见。
清单 9. 用于显示图表的 HTML 图像
<img id="chartImage" style="display:none;" src=""/>
|
您应该查看 chart.maker 示例项目中的 /public/index.html 文件,看看所有这些 markup 和代码。接下来的小节将谈到面向 Ajax 的 JavaScript(也被包括在该文件中),它用于操纵 UI 元素,以显示反映用户输入的图表。
与 REST API 的交互就是实现 createCharts()函数,使之读取所有表单输入值,将它们打包到一个 JSON 对象中,并将 JSON 对象作为 HTTP POST 请求的一部分发送到 charts资源。HTTP POST 请求完成后,您将从 Location响应报头读取图表 URL,并设置(重置)图表图像的源。清单 10 显示了实现这一点的代码。
清单 10. 使用 Ajax 创建和显示图表
function getHttpClient()
{
var hasXHR = window.XMLHttpRequest;
return hasXHR ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
}
function createChart()
{
// step 1
var chart = {
title: getValue("chartTitle"),
type: getSelection("chartType"),
height: getValue("chartHeight"),
width: getValue("chartWidth"),
data: getValues("chartData"),
xaxis: getValues("xaxis"),
yaxis: getValues("yaxis")
};
// step 2
var http = getHttpClient();
http.open("POST", "/resources/charts", true);
// step 3
http.onreadystatechange = function() {
if (http.readyState != 4)
return;
var chartImage = document.getElementById("chartImage");
chartImage.src = http.getResponseHeader("Location");
chartImage.style.display = "block";
}
// step 4
http.send(JSON.stringify(chart));
}
|
我们来逐步讲解这段代码:
在 createCharts()中,首先做的事情是使用适当的名称 - 值对创建一个 JSON 对象。getValue(s)方法是类似于 清单 7中的 getSelection()方法的简单实用程序。它们的实现非常普通,可以从示例项目中查看它们。这里要特别注意的是,字段名称与 /app/scripts/charts.groovy 文件期望的名称相匹配,并且值使用适当的格式。
第二步是创建一个 XMLHttpRequest对象,并发起一个对 /resources/charts 的 HTTP POST 请求。getHttpClient()方法隐藏有一些条件,以确保为适当的 Web 浏览器实例化适当的类。
第三步是定义发送请求和收到响应之后的动作。在这个例子中,您将获取 Location报头的值,并使用它设置 chartImage.src的值;然后,修改 chartImage样式,使之不再对用户隐藏。
最后一步是发送 HTTP POST 请求。这包括将 JSON 对象转换成可放入 HTTP POST 请求体中的字符串。由于没有标准的 JSON-to-string API,所以使用来自 http://json.org 的开源库。createChart()最后的 JSON.stringify()API 调用是在一个名为 json2.js 的文件中定义的,该文件可以从 http://www.json.org/json2.js获得。您应该从 http://json.org 下载这个 JavaScript 库,并将它添加到 /chart.maker/public 目录。一旦这个库准备就绪,createCharts()的最后一行将顺利运行。
您看到了如何创建精巧的 mashup 应用程序,并且在此过程中使 Google Charts API 更易于在 Zero 应用程序之间重用。示例 Ajax 界面只涉及可视化图表构建器中的一些基本特性,但是服务器端代码可以支持您想要添加的任何其他特性。在将 RESTful API 用于宝贵的服务和数据方面,Zero 对 Groovy 脚本编制的集成再次被证明可以节省大量的时间。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| 本文的示例应用程序 | zero-chart-maker.zip | 7KB | HTTP |
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
-
了解 Google Charts API必须提供什么特性。
-
需要 Project Zero 的简介?请参阅“用 Project Zero 开发应用程序 : Project Zero 和 PHP 入门”(developerWorks,2008 年 1 月更新)。
-
developerWorks Ajax 资源中心包含了可帮助您开始开发精巧的 Ajax 应用程序的工具、代码和信息。
- 随着 Web 2.0 成为开发界的热门领域,您将在 Web 开发专区找到越来越多的资料。
- 需要跟上 PHP 的脚步?看看我们的
PHP 项目中心。
-
developerWorks Project Zero space提供很多可以帮助您立即开始使用 Project Zero 进行开发的资源。
-
在 developerWorks 上可以找到不断增加的 Project Zero 内容。
获得产品和技术
-
下载 Project Zero M4,重新创建本文演示的项目。
讨论
-
加入 projectzero.org论坛。
-
developerWorks
blogs:加入 developerWorks 社区。
