利用Grails搭建Feedlr.com网站

Feedlr:feed驱动的多平台微博客机器人平台

微博客是由Twitter 创造出的一种web 2.0时代的新事物。在微博客上,人们 使用简短的语言随时随地的发表消息,并可以即时地受到好友的消息。由于易用 ,实时等特点,Twitter在06年推 出至今逐步升温,已经拥有超过300万用户。 特别在08年中,Twitter一改起步阶段geek玩具的角色,明显地向主流进化。随 着Twitter的兴 起,也出现了非常多其他的微博客。仅国内就有叽歪、饭否、以 及做啥等等。微博客的兴起提供了一种全新的在线沟通方式。

Twitter作为微博客的 鼻祖和最成功的例子,其优秀的API接口功不可没。通 过Twitter API,开发者们开发出了众多新奇又好用的Twitter第三方应用。我开 发Feedlr的出发点是建立一个让用户可以自行定制feed机器人的服务,核 心功 能类似Twitter上颇受欢迎的twitterfeed,并且可以同时Twitter,叽歪,饭否 以及做啥共4种微博客平台。

通过 Feedlr,用户可以建立微博客广播帐号,来随时追踪自己感兴趣的 RSS/Atom Feed内容。一旦有更新,Feedlr就会自动把新的内容发送到指定的微 博客平台上。Feedlr上线至今,用户们建立了自定义的新闻播报机器 人,DIY的 免费天气预报机器人,不同微博客之间的消息同步机器人,甚至国内地震情况实 时监控机器人等等。而通过国内微博客服务的短信通知服务,以上所有 的Feed 内容国内用户都可以免费在手机上通过短信接收到。

Grails框架的选择

Grails是一个崭露头角的基于 Groovy语言,运行与JVM之上,设计上类似于 Rails的快速web开发框架,在08年初刚推出1.0版。通过Groovy语言和创新的架 构,Grails把成熟的企业级JEE开源组件Spring,Hibernate等巧妙地整合起来, 使用类似Rails的“按约定设计”(design by convention)理念捆绑成一套完整 的web开发框架。JEE开发过程的繁琐被Groovy灵活多变的动态特性和按约定设计 带来的精简配置所取代, 而又保留了企业级组件在稳定和性能方面的优势,可 以说是把Rails式的快速开发带给了水深火热中的JEE开发者们。我来自JEE背景 ,对Groovy语 言也有一定基础,选用Grails搭建Feedlr是比较自然的选择,同 时也是为了在一个没有过多约束的真实项目中体验Grails的完整开发过程。

如何用Grails实现Feedlr的核心功能Feedlr的核心功能

Feedlr的核心功能主要包括定时查询用户提供的feed的更新,把更新的feed 内容发布到微博客,再加上用来增强用户体验的多处AJAX实现以及OpenID登录等 。这里逐一对这些功能的实现做一下介绍。

定时查询feed更新

Feedlr 最核心的功能就是定时轮询用户提交的feed,发现新增的条目,从而 通过微博客API发送到微博上去。只要使用Grails的Quartz插件就可以非常 方便 的实现这一功能。Quartz是一个用途广泛的开源Java库,用于精确地控制定时任 务。由于兼容Unix Cron语法,Quartz的功能非常强大。而在Grails中,Quartz 是框架自带的核心插件之一,通过Quartz插件来执行定时任务非常方便。 新建 一个Quartz定时任务,只需要在Grails项目根目录下执行

grails create-job

根 据提示输入job名称,Grails就会自动在grails-app/jobs/目录下生成一 个新的job程序文件。Grails job都是以XXXJob.groovy命名,存放在grails- app/jobs目录下,Grails启动时会自动遍历jobs目录,定时执行每个定 义好的 job。一个job文件用来定义一种定时执行模式,通过Unix Cron语法来定义定时 逻辑。例如,Feedlr用于轮询feed的job大致是这样的:

class UpdateFeedsJob {  def feedService   def cronExpression = "0 * * * * ?" //每分钟执行一次  def execute() {      feedService.updateFeeds()  }}

Cron 表达式“0 * * * * ?”表示每分钟执行一次。需要执行的逻辑通过定 义一个execute()方法来指定。其中feedService是已经定义好的用来查询feed更 新的一 个Grails Service类,使用Rome来解析feed。注意此处不需要实例化 feedService变量,只要通过按约定设计的规则定义需要使用的 Service的变量 名,Grails会自动找到FeedService这个Service类,注入到UpdateFeedsJob中, 并把 Service实例付给feedService变量,听起来很神奇吧。这样,Grails就会 每分钟触发一次UpdateFeedsJob,来查询 feed更新了。

发布feed更新到微博客

目前流行的微博客API都是已REST风格设计,通过GET和POST方法来得到或者 更新内容的。例如发布一条消息到Twitter,就是通过POST方法发送到Twitter指 定的API地址,简化的代码实例如下:

def conn = new URL ('http://twitter.com/statuses/update.xml').openConnection()conn.setRequestProperty ('Authorization', 'Basic ' + 'username:password'.bytes.encodeBase64())conn.requestMethod = 'POST'conn.doOutput = truetry{  conn.outputStream.withWriter('UTF8'){           it << "status=" << newMessage   }}catch(Exception e){   ...}

以上Groovy代码很清晰易读。通过Twitter RESTful API发布新消息需要使用 Http Basic验证用户登录信息,所以这里按照Basic验证规范在请求中加入了验 证数据。其中encodeBase64()方法是Grails提供的神奇的 动态方法,对于合适 类型的对象在Grails程序中直接就可以使用这些动态方法,其他的编码方法还包 括encodeAsURL()等。

Ajax

在web 2.0时代没有Ajax的网站是不完整的。幸运的是,在Grails中使用Ajax 非常方便。通过Grails内建的多才多艺的render方法,就可以轻松地给前端Ajax 请求返回任何形式的输出。例如,

直接返回简单的纯文本字串

class FooController{...   def ajaxResponse = {     ...    render("This is an Ajax response.")   }

指定返回内容的格式和编码

render(text:"some xml",contentType:"text/xml",encoding:"UTF-8")

返回模板内容

render(template:"feeds", model:[feeds:feeds], contentType:"text/html", encoding:"UTF-8")

返回JSON,直接自动转换一个object为JSON

import grails.converters.*...def jsonObj = [object:[collection:[[name:‘value1′],[name:‘value2 ′]]]]render jsonObj as JSON

返回JSON,通过JSON builder DSL直接构造JSON数据

render(contentType:‘text/json’, , encoding:'UTF-8'){     studio(name:‘Pixar’,website:‘pixar.com’)     films{         film(title:‘Toy STory’,year:‘1995′)         film(title:‘Monsters, Inc.’,year:‘2001′)         film(title:‘Finding Nemo’,year:‘2003′)     }}

OpenID支持

Feedlr支持使用OpenID登录。由于Grails社区已经提供了OpenID插件,通过 Grails的插件机制,实现OpenID支持也是一件轻松的事情。

首先,安装OpenID插件,在Grails应用根目录执行命令:

grails install-plugin openid

然后,使用openid插件提供的taglib来编写openid登录表单

         ...

OpenID 插件代为处理了具体的OpenID登录验证过程,在 中,通过success参数和error参数指定登录成功或失 败以 后重定向到哪个controller action。登录成功后,就可以在controller中直接 得到当前登录的openid信息。

def penid = session.openidIdentifier

当然,需要实现完整的OpenID和普通帐号的整合还有更多工作要做,包括把 登录的OpenID和已有的普通帐号关联起来,从普通帐号添加OpenID信息等。这些 都是需要开发者根据自己的情况自行实现的。

测试

测 试是开发一个完整项目不可缺少的部分,幸运的是Grails已经为开发者考 虑到了这点,测试Grails程序也能像开发一样轻松。Grails中的测试建 立在 Groovy testing的基础上,通过使用Groovy来编写JUnit测试代码,减轻程序员 的负担。Grails中的测试分为unit test和integration test两种,两者的区别 主要在于unit test是相对独立的测试,而integration test执行的时候Grails 会按照实际运行的方式启动框架程序。建立一个unit test或者integration test各自只需要一条命令即可。

grails create-unit-testgrails create-integration-test

Grails 会自动在grails-app/test/unit或者grails-app/test/integration 下面建立相应的 XXXTests.groovy文件。具体的test case定义在 XXXTests.groovy里,通过定义继承groovy.util.GroovyTestCase的类来实现, 这些其实都是 Groovy测试的内容,通过JUnit方式编写测试代码即可。

准备好了test case之后,Grails同样已经为你准备好的命令来自动执行测试 。

grails test-app

执行这条命令,Grails就会自动按照unit test到integration test的顺序来 执行定义好的所有test case,并将测试结果整理成HTML格式展现出来。test- app命令还有更多具体用法,可以参考Grails文档。

Feedlr的部署

使用Grails的开发过程是很令人感到愉快的。那么,一切都搞定以后,怎么 部署呢?

Grails 文档中说明Grails经测试可以部署到大多数常用的Java应用服务器上 ,但是具体有关部署的资料文档比较缺乏。Feedlr选择的是Tomcat 6,相对来讲 比较常用,资料也比较丰富。准备部署Grails应用的时候,首先通过Grails把项 目打包成war文件。

grails prod war feedlr.war

这 里,”prod”参数用来指定打包的时候使用Config.groovy里针对生产环境 的配置。部署环境的配置在Config.groovy中设定,包 括”prodcution”, “development”和”testing”三种,主要用于对不同环境指定不同的数据源和特 定的环境变量。具体用法可以 参考Grails文档。war命令默认的打包环境就 是”prod”,所以次数”prod”也可以省略。如需指定其他环境只需要将”prod”替换 成”dev”或者”test”即可。

最后指定war文件的文件名是可选的。在Tomcat下如果想让应用跑在URL根路 径下,可以指定文件名为ROOT.war。打包完成后,把war文件复制到Tomcat应用 目录下,启动Tomcat,正常的话Grails应用就能跑起来了。

在 系统性能和伸缩性方面,我其实没有花太多力气去优化。最主要的优化工 作就是在内存占用方面。Feedlr目前使用的是一台540MB内存的VPS服务器, 在 初期曾使用340MB内存的配置,遇到了内存资源紧张的问题,导致JVM性能底下。 由于Feedlr的特定用途,需要解析大量feed内容,所以在内存 方面要求不低。 后来经过一系列的优化措施,目前在这个环境下运行的相对比较稳定了。我之前 也总结过一些Grails服务器优化的经验,有兴趣的朋友可以参考我的这篇博客文 章。

实际开发中的一些困难

在Feedlr的开发中,可以体会到目前阶段使用Grails进行完整Web项目开发的 一些困难和问题。

开发环境的不完善

Feedlr 是在Eclipse加上Groovy插件的环境下开发的。但是这个环境目前还 非常不完善,主要是Groovy插件的可用程度还比较低,而且没有 Grails支持, 不支持GSP语法等,只是能够支持Groovy语言,加上Eclipse本身的强大功能,能 够给开发提供一定帮助。不过好在使用 Groovy语言开发比Java要省力不少,所 以不需要非常强大的IDE也可以不错的完成任务。IDE方面另外的选择主要包括 IntelliJ IDEA和NetBeans。简单来讲收费的IDEA对Groovy/Grails的支持最为完 整强大,但是代价也不菲。开源方面的选择,Eclipse 方面还是比刚刚开始支持 Groovy的Netbeans好过不少。

Grails本身尚不够成熟

在开发过程中也遇到过若干 Grails的bug,有的bug甚至导致某功能无法正常 运行。使用一个尚不成熟的框架,遇到bug也是正常的事情。解决bug的话基本上 可以先到 Grails邮件列表里提问和寻找答案,需要的话提交bug报告到Grails官 方JIRA,提供bug数据等待修复。不过如果遇到紧急问题,还是自己动 手更好。 可以从Grails主页下载带源码的Grails安装包,就可以直接调试bug并编译修改 代码,这样不用等官方发布下一个小版本就可以直接解决问 题了。在Feedlr开 发过程中遇到过若干比较紧急的bug,我随着bug报告也提供过若干补丁程序,在 最新的Grails 1.0中都已被集成。在这里也要建议大家在使用过程中多多提交 bug报告和提供补丁程序,这是良好的参与建设开源社区的方式。

总结

要 完整地实现Feedlr显然还有很多工作要做,但Grails确实大大减轻了程序 员编码工作的负荷。通过grails stats命令可以看到,除去测试代码,feedlr最 终的代码规模约是1.9kloc。对于一个完整地具备了包括全文检索,RSS/Atom feed生成(Feedlr提供最新机器人服务列表的feed),Tag标签功能,OpenID+普 通登录方式整合等功能的web 2.0网站来说,这确实意味着我省去了不少打字的 工夫,避免了传统JEE繁琐的开发方式。

那么,Grails到底是不是JEE世界的圣杯呢?我将在本系列的下篇文章中进一 步进行分析。

可以以心感悟,以此沉淀,足矣;耳听佳音,目极美好,

利用Grails搭建Feedlr.com网站

相关文章:

你感兴趣的文章:

标签云: