Java 开发 2.0: 针对 Google App Engine 的 Gaelyk

基于 Groovy 的框架加速 Google App Engine 上的开发工作

在 Google App Engine 推出后,各类框架随之涌现,旨在加速该引擎上的应用程序开发工作。使用 Groovy 编写的 Gaelyk 框架就属于其中之一,它的作用是简化利用数据存储的轻量级应用程序的开发。并且,它所提供的可伸缩性也令人印象深刻。

Andrew Glover, 作家和开发人员

Andrew Glover 是具有行为驱动开发、持续集成和敏捷软件开发激情的开发人员、作家、演说家和企业家。他是 easyb 行为驱动开发(Behavior-Driven Development,BDD)框架的创建者和三本书的合著者:持续集成Groovy 在行动Java 测试模式。您可以通过他的博客与他保持一致并在 Twitter(http://twitter.com/aglover)上关注他。



2010 年 1 月 25 日

系列 将探讨对于如今及未来的 Java™ 开发的发展起决定作用的各个技术方面。Java 开发 2.0 的前提开发速度将越来越快,这要归功于开源领域中的创新以及硬件的商业化。您可以租借其他人的硬件平台来托管自己的应用程序(主要使用开源库、工具和框架来装配),成本只包括获取和维护自己的基础设施。

关于本系列

从 Java 技术首次亮相以来,Java 开发的格局已经发生了巨大的变化。得益于成熟的开源框架和可靠的租用式部署基础设施,现在已经可以迅速经济地汇编、测试、运行和维护 Java 应用程序了。在本系列中,Andrew Glover 将探索使这种全新开发范例成为可能的各种技术和工具。

本系列的第一期 “使用 Google App Engine” 讨论了免费租借 Google 的基础设施来托管您的 Java 应用程序(不过会牺牲少许灵活性)的概念。在后续文章中,您了解了 App Engine 和 Amazon 的 EC2 之间的差异。上个月的文章 “通过 CouchDB 和 Groovy 的 RESTClient 实现 REST” 调查了关系数据库的潜在替代方案:CouchDB。CouchDB 缺少模式以及其面向文档的特性对您来说可能有点新鲜,但您已经目睹了 Google App Engine 实现的另一个无模式数据存储。

本文又将回过头来讨论 Google App Engine。开源世界已经跳上了 App Engine 列车,针对该平台的应用程序开发加速架构层出不穷。您将了解 Gaelyk 框架如何利用本系列已经介绍的许多技术来进一步简化应用程序的开发。

轻量级是全新的趋势

虽然 Google 的基础设施大多是可以免费使用的(当存储空间和带宽达到 500MB,每月页面访问量达到大约 5 百万次时便要收费),但它会在一定程度上牺牲一些灵活性。Google 的基础设施支持 Java 技术,但这并不包括所有 的核心 Java 库和相关开源库。App Engine 是一个平台 — 您需要基于它进行开发。但不足为奇的是,开源创新将帮助克服采用 Google App Engine 过程中的障碍。

Gaelyk 框架就是这种项目的一个典型,其目的是加速轻量级应用程序的开发,即使用 Groovy 开发的、适当利用模型-视图-控制器 (MVC) 模式的应用程序。在 Groovy 的魔力下,Gaelyk 将为 App Engine 的 API 注入一些易用性因素。此外,您还可以将 Gaelyk 与针对 Eclipse 的 Google App Engine 插件结合使用。快速开发和部署 Google App Engine 应用程序将变得非常简单。

Google 持久性

Google App Engine 的持久性实现对于开发人员来说是隐藏的,但至少可以确定的是它并非关系数据库。但开发人员可以借助 Google 的平台通过普通的 Java Data Objects (JDO) 代码或者甚至通过 Google 的低级持久性 API 来保存、读取、更新和删除持久对象。

通过 CouchDB 和 Groovy 的 RESTClient 实现 REST” 利用一个停车罚单系统演示了面向文档的数据库的特性。在本文中,我将继续创建一个支持创建、更新和删除停车罚单的 Web 应用程序。Google 持久性架构不是面向文档的,但其无模式特性实现了一个更加灵活的模型。因此,Web 将尽可能准确地建立一个停车罚单模型,这需要获取:

  • 警官姓名
  • 日期
  • 位置
  • 违规情况
  • 任何相关注释

我保留位置为一个普通的文本框,因为一些人可以使用各种方式来表示违规发生的位置 — 比如在 Best Buy 的停车区 或者在 18 号街和 D 大街的拐角处。实际上,我不会尝试描述一个特定格式,因为它不一定适合这个域。

首先,您需要安装针对 Eclipse 的 Google App Engine 插件(参见 “使用 Google App Engine” 了解详细步骤)。您还需要从项目的网站下载 Gaelyk JAR 文件(参见 参考资料)。记住这个下载的位置,因为您随后需要将它移动到一个特定的目录中。

Gaelyk 框架依赖于 Groovy,因此您还需要最新的 Groovy 发行版:在撰写本文时,它是一个简单的 JAR 文件,即 groovy-all-1.6.5.jar(参见 参考资料)。最后,您需要通过 Google App Engine 管理面板创建一个应用程序 ID。(如果愿意,您可以重用在 “使用 Google App Engine” 中创建的应用程序 ID)。

接下来,在 Eclipse 中创建一个新的 Google Web Application Project,单击 Next 按钮并填入适当的信息。确保取消选中了 Use Google Web Toolkit 选项,如图 1 所示,因为您不需要它:

图 1. 在 Eclipse 中创建一个 Google Apps Project
在 Eclipse 对话框中创建一个新的 Google Apps Project

单击 Finish 按钮,您将建立好代码基础。

现在,将 Groovy 和 Gaelyk JAR 复制到新创建项目的 war/WEB-INF/lib 目录中,如图 2 所示:

图 2. Gaelyk 的必需库
新创建项目的 war/WEB-INF/lib 目录,Groovy 和 Gaelyk JAR 已复制到其中

要配置 Gaelyk,您需要为 Google App Engine 提供一些额外的信息,方法是编辑 WEB-INF/appengine-web.xml 文件。将您的应用程序 ID 添加到此文件顶部的应用程序部分,并添加一些 XML,如清单 1 所示:

清单 1. 对 App Engine 配置的必要更新
<static-files>
 <exclude path="/WEB-INF/**.groovy" />
 <exclude path="**.gtpl" />
</static-files>

添加这些内容将防止 Google App Engine 静态提供最终在使用 Gaelyk 时会创建的各种文件。如您所见,Gaelyk 将利用一个模板模型。因此,使用 .gtpl 扩展名的文件将类似于 JavaServer Pages (JSP) 并且将通过框架而非 App Engine 进行处理。

接下来,打开 web.xml 文件。该文件也可以在 WEB-INF 目录中找到。它是标准的 Web 应用程序配置文件。(您将在初次访问 App Engine 和 EC2 时操作此文件。)该文件需要将各种模式映射到特定的 servlet,因此根据清单 2 调整您的文件:

清单 2. 更新后的 web.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
 <servlet>
  <servlet-name>GroovletServlet</servlet-name>
  <servlet-class>groovyx.gaelyk.GaelykServlet</servlet-class>
 </servlet>
 <servlet>
  <servlet-name>TemplateServlet</servlet-name>
  <servlet-class>groovyx.gaelyk.GaelykTemplateServlet</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>GroovletServlet</servlet-name>
  <url-pattern>*.groovy</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
  <servlet-name>TemplateServlet</servlet-name>
  <url-pattern>*.gtpl</url-pattern>
 </servlet-mapping>
 <welcome-file-list>
  <welcome-file>index.gtpl</welcome-file>
 </welcome-file-list>
</web-app>

注意,web.xml 文件指定 welcome 文件为 index.gtpl;因此,将 Eclipse 插件为您生成的 index.html 文件重命名为 index.gtpl。(如果使用 Windows® 操作系统,则只需选择文件并按下 F2。)

安置好适当的库并正确配置了两个 XML 文件之后,您可以验证一切是否运行正常,这需要编辑 index.gtpl 文件让它匹配清单 3 的内容:

清单 3. 一个简单的 GTPL 文件
<html>
 <head><title>A Simple GTPL</title></head>
  <body>
   <b><% print "Hello Gaelyk!".replace(" ", " from ") %></b>
   <p>
   <ol>
    <% def wrd = "Groovy"
       wrd.each{ letter ->
    %>
    <li><%= letter %></li>
    <% } %>
   </ol>
   </p>
  </body>
</html>

可以看到,Gaelyk 中的 GTPL 文件(或 Gaelyk/Groovy 模板)类似于 JSP: 您可以在 scriptlet 中添加行为(在本例中,添加的行为是 Groovy)。注意,稍后您也可以使用闭包和引用变量。

保存您的 index.gtpl 文件在 Eclipse 中选择项目的基本目录,单击鼠标右键,选择 Run As 并选择包含蓝色 G 徽标的 Web Application 选项,如图 3 所示:

图 3. 作为 Google Web 应用程序运行
选择包含蓝色 G 徽标的 Web Application 选项

默认情况下,此启动程序将在端口 8080 上启动一个本地 Jetty 实例。如果要更改端口,请选择 Run Configurations 选项并通过插件提供的选项面板配置端口。

运行 Gaelyk Web 应用程序的本地实例之后,打开一个 Web 浏览器并访问 http://localhost:8080。index.gtpl 的输出应如图 4 所示:

图 4. Hello world!
index.gtpl 在 http://localhost:8080 中的输出

非常简单,不是吗?


简单的持久性

罚单系统非常简单。它提供了一个 Web 表单,可用于创建罚单以及在列表中查看、删除和编辑罚单。我首先将通过 Gaelyk 模板创建一个简单的 HTML 表单,并将它命名为 createticket.gtpl。如图 5 所示,这个表单将尝试捕获与各停车罚单相关的数据:

图 5. 一个简单的罚单表单
一个简单的空白罚单表单

表单将提交给一个 groovlet;相应地,在项目的 WEB-INF 目录中创建一个 groovy 文件夹。您的 groovlet 将存放在此处。(您在 “使用 Google App Engine” 中也完成了此操作。创建罚单(create-ticket)表单将提交给一个 createticket.groovy 文件。在新创建的 groovy 目录中创建此文件。

毫无疑问,您可以在 Gaelyk 中使用 JDO 和 Java Persistence API (JPA) 代码,但是也可以采用另外一种方法来与底层数据存储交互:即使用 Google 的 Entity 对象。Gaelyk 团队已凭借一些 Groovy 魔力简化了持久对象的操作,从而增强了 Entity 对象。

在本例中,我希望获取通过 createticket.gtpl 页面提交的表单元素,并在系统中创建一个新罚单。通过使用 Entity 类,我不需要定义一个类似于 POJO 的对象来表示罚单(就像我在 “使用 Google App Engine” 中创建 Triathlon JDO 对象时所做的一样)。我可以采用 Groovy 的方式建立一个罚单模型,并毫不费力地保存它。

因此,我可以通过 Gaelyk 的 params 对象(Grails 也以某种形式提供了此对象)获取由表单提交的参数,并创建一个 Entity 实例,如清单 4 所示:

清单 4. 创建一个 Entity
def formatter = new SimpleDateFormat("MM/dd/yyyy")
def offensedate = formatter.parse("${params.of_month}/${params.of_day}/${params.of_year}")

def ticket = new Entity("ticket")
ticket.officer = params.officer
ticket.license = params.plate
ticket.issuseDate = offensedate
ticket.location = params.location
ticket.notes = params.notes
ticket.offense = params.offense

注意,ticket 变量是 Entity 的一个实例。"ticket" String 表示的就是这种实体。它可以非常便捷地搜索罚单。接下来,我将自动为与罚单相关的 Entity 实例分配属性值。现在,ticket.officer 表示通过 Web 页面表单提交的 officer 参数的值。由于该表单包含三个日期字段,我也使用 SimpleDateFormat 创建一个日期实例,并将该值设置为 issueDate

至此,我已经创建一个用于表示罚单的对象。现在,我要做的就是使用以下代码保存它:

ticket.save()

现在,我已经持久化了一个罚单,我将把用户定向到一个可查看罚单的页面。这也非常简单。我只需要定向到 view-ticket Groovlet(以便处理):

redirect "viewticket.groovy?id=${ticket.key.id}"

如您所见,我已经创建了一个名称为 id 的参数,并将它设置为已保存罚单(由 Google App Engine 生成)实例的键。可见,create-ticket Groovlet 非常简明和强大 — 这得益于 Gaelyk。


简易视图

在上一个示例中,当我创建了 ticket 实例之后,我继续将请求重定向到另一个 Groovlet — 它可以简化罚单的查看过程。在此 Groovlet 中,我编写了一个 Google App Engine “read”。传递的 id 将用于查找新创建的实例。在本例中,我将使用 Google 的 KeyFactory,它用于创建 Google 的 Key 对象的实例。然后,Key 将用于通过 datastoreService 查找相应的罚单实例,而 Gaelyk 已将它们添加到框架中的任何 Groovlet 实例中,如清单 5 所示:

清单 5. 查看 Entity
import com.google.appengine.api.datastore.KeyFactory

if (params["id"]) {
 def id = Long.parseLong(params["id"])
 try {
   def key = KeyFactory.createKey("ticket", id)
   def ticket = datastoreService.get(key)

   request.setAttribute "ticket", ticket

   forward "viewticket.gtpl"

   } catch (Throwable t) {
    //forward to some error page...
   }
} else {
 forward "index.gtpl"
}

找到相应的 ticket 之后,罚单将被添加到 HTTP request 对象(它已经出现在 Groovlet 中),然后将处理转交给 viewticket.gtpl 页面。与 Web 应用程序中的任何其他 JSP 一样,这个 Web 页面将显示与传入罚单相关的相应属性。

从清单 6 中可以看出,Gaelyk 支持 includes。也就是说,在您的 .gtpl 文件中,您可以包括其他文件,就像普通 JSP 文件一样。同样,所有 .gtpl 文件都有一个 HTTP Request 对象的实例可用(通过 request 变量)。

清单 6. 查看 Entity GTPL
<% include "/WEB-INF/includes/header.gtpl" %>

<% def ticket = request.getAttribute("ticket") %>

<div class="info">
 <h2>Parking Ticket</h2>
 </div>

<table>
<tr>
	<th>Issuing Officer</th>
	<th>Vehicle Plate</th>
	<th>Date</th>
	<th>Offense</th>
	<th>Location</th>
	<th>Notes</th>
  </tr>
 <tr>
	<td>${ticket.officer} </td>
	<td>${ticket.license}</td>
	<td>${ticket.issuseDate}</td>
	<td>${ticket.offense}</td>
	<td>${ticket.location}</td>
	<td>${ticket.notes}</td>
  </tr>
 </table>

<% include "/WEB-INF/includes/footer.gtpl" %>

至此,您或许可以发现 Gaelyk 使得在 Google App Engine 上创建轻量级 Web 应用程序轻而易举。并且,操作 App Engine 的持久库也变得再简单不过。您在操作 Entity 时使用的低级 API 确实需要花一些时间习惯。查询需要一些思考(在某些方面类似于使用 CouchDB 执行查询)。举例来说,查看已创建罚单的列表需要一些如清单 7 所示的代码:

清单 7. 查看一组 Entity
import com.google.appengine.api.datastore.Query
import static com.google.appengine.api.datastore.FetchOptions.Builder.withLimit

try {
 def query = new Query("ticket")
 query.addSort("issuseDate", Query.SortDirection.DESCENDING)
 def preparedQuery = datastoreService.prepare(query)
 def tickets = preparedQuery.asList( withLimit(10) )

 request.setAttribute "tickets", tickets
forward "index.gtpl"
} catch (Throwable t) {
 forward "index.gtpl"
}

清单 7 使用了 App Engine 的 Query 对象。如您所见,您可以为查询添加类似于排序的特性,甚至还能限制返回结果的方式。不需要使用 SQL,但需要确保数据已存储并且可以检索,只存在少许不同。

如 “使用 Google App Engine” 所述,部署到云的过程也非常简单。通过插件,只需要单击 Deploy App Engine Project,其余的事情就由 Google 来完成了。事实上,您可以 下载 本文的代码来完成此操作。代码将填入一些间隔,因此我无法在一篇文章列出所有代码。举例来说,我实现了删除罚单的功能,并且用户与罚单之间的交互也稍有增强,因此您可以或多或少感受到 Gaelyk 的效果。


快速开发更加轻松

受到开源技术支持的云和无模式数据存储无疑是未来 Java 开发中的一部分。两者的采用门槛都较低;在本文的示例中,硬件和软件都是免费的。并且,一旦 Google 开始收费,那么肯定要自力更生 — 每月 5 百万的点击率是巨大的流量。Gaelyk 框架加快了 Web 开发的步伐。Java 开发始终在日臻完善,不是吗?


下载

描述名字大小
本文示例的源代码j-javadev2-6.zip8.3MB

参考资料

学习

  • Gaelyk:了解关于 Google App Engine for Java 这个轻量级 Groovy 工具箱的更多信息。
  • Google App Engine:访问 Google App Engine 的主页。
  • Java 开发 2.0:使用 Google App Engine”(Andrew Glover,developerWorks,2009 年 8 月):理解 Java 开发 2.0 以及如何通过 Google 的 App Engine for Java 将其概念迅速转化为成果。
  • 实战 Groovy(Andrew Glover 和 Scott Davis,developerWorks):本系列探究 Groovy 的实际应用,以帮助您了解如何成功应用它们。
  • 云计算:访问 IBM® 云计算中心,获取关于云的大量资料。
  • 浏览 技术书店 获得关于各类技术专题的书籍。
  • developerWorks Java 技术专区:这里有数百篇关于 Java 编程各个方面的文章。

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Java technology
ArticleID=464119
ArticleTitle=Java 开发 2.0: 针对 Google App Engine 的 Gaelyk
publish-date=01252010