使用百度Clouda框架创建RSS阅读器应用

来源:互联网 发布:通达信软件电脑版 编辑:程序博客网 时间:2024/05/01 15:37

什么是Clouda?

Clouda是百度的一款开源NodeJs轻应用框架,拥有百度强大的技术支持,实现快速开发、优化SEO、易部署等特性,提供简单易用的依赖管理模块化开发环境。

详细信息,请猛击Clouda主页:http://cloudajs.org



安装和使用Clouda

安装Clouda

Clouda是基于node.js的Webapp开发框架,在使用Clouda时需要安装node.jsMongoDB,如果您没有安装请参考本文档环境搭建部分。

使用下面命令安装Clouda

npm install -g sumeru

使用Clouda创建工程

sumeru init ./myproject

运行Clouda

在运行Clouda前需要启动MongoDB,如何启动MongoDB请参考本文档环境搭建部分。

cd myprojectsumeru start

环境搭建

安装node.js

Clouda是基于node.js的开发框架,所以我们首先需要安装node.js

  • 下载node.js,地址:http://nodejs.org/download/

  • 安装node.js

安装MongoDB

在本地Clouda使用mongoDB作为数据库,按照下面的步骤安装并启动MongoDB

  • 下载mongoDB,地址:http://nodejs.org/download/

  • 解压下载的文件夹,进入解压后的目录,在目录下创建"data"目录,并在创建的"data"目录下创建"db"文件夹

  • 进入根目录下的bin/,使用下面的命令启动MongoDB

    sudo ./mongod -dbpath ../data/db

注意:在运行Clouda应用前必须启动MongoDB


现在开发一款基于Clouda框架的RSS阅读器实例。


首先,我们按照官方的步骤,安装好Clouda和MongoDB。

然后我们进入到app/controler/package.js 编辑该文件:

sumeru.packages('RSSreader.js')

这里定义了一个RSSReader的控制器(实际上是文件,但一般来说要从文件名中可以读取该文件的用途)。

接着我们补充这个RSSreader.js的实际内容:

sumeru.router.add({pattern: '/RSS',action: 'App.RSSReaderAction'});//上面的配置,pattern 指定了一个路由的路径匹配,意思就是,访问你应用的/RSS/后面的位置,路由就被匹配到了。//但匹配后做什么?别急,action 指定了一个控制器:App.RSSReaderAction,这个控制器就是用来执行相应的动作,如下。App.RSSReaderAction = sumeru.controller.create(function(env, session) {//定义试图文件名var view = 'html';var processDoc = function(doc){//文档处理方法var html = '';var xml = $.parseXML(doc);var $doc = $(doc);var items = xml.getElementsByTagName('item');$.each(items,function(index,element){var title = this.getElementsByTagName('title')[0];var link = this.getElementsByTagName('link')[0];var h3 = '<h3 style="border-left:solid 3px #99CCFF;padding:10px 5px;"><a style="color:#333;" href="'+link.textContent+'" target="_blank">'+title.textContent+'</a></h3>';var description = '<div style="background:#EEE;padding:5px;" class="f-rrs-item-content">'+this.getElementsByTagName('description')[0].textContent+'</div>';html+='<li>'+h3+description+'</li>';});return '<ul style="list-style:none;">'+html+'</ul>';}var getData = function() {//这里负责获取并解释从路由器传递过来的参数(我们这里需要RSS网址)var argLength = env.arguments.length;var url = '';console.log('arg length -> '+argLength);for(var i=1;i<argLength;++i){var arg = env.arguments[i]if(arg=='http:'||arg=='https:')arg+='//';else if(i!=argLength-1)arg+='/';url+=arg;}console.log('url -> '+url);        //分析完之后我们要使用subscribe去做处理        //每个subscribe都要对应一个publishenv.subscribe('pubhtml', url , function(newsCollection){//console.log(ewsCollection.getData());            var obj = newsCollection.getData()[0];            //使用文档处理方法,返回一条压缩过的html代码            var content = processDoc(obj['body']);            //session与 block 进行数据绑定            session.bind('htmlBlock', {                'htmlContent' : content            });        });}env.onload = function(){//onload 事件是整个Controler生命周期中第一个事件,用于进行数据处理return [getData];}env.onready = function(){//onready 是 Controler生命周期的第三个事件,在这个环节代表View已经被渲染完成,可以做里面的DOM操作}env.onrender = function(doRender){//onrender 是 Controler生命周期的第二个事件,这个环节是开始渲染View        doRender(view, ['rotate','left']);    };});


如果你阅读完代码后,你会发现一个在网页前端上最常用的字符变量$,这个一般是在jQuery使用最多(很多热门的JS库都占用$符号,不只是jQuery),在这里我习惯了使用jquery去操作DOM,所以,我要实现引用jQuery的库,否则上面的代码根本不能正常执行。


首先我们到app下建立一个jslib的文件夹,然后将jQuery.js放到里面(如果不知道怎么获取jQuery.js的话,请自行百度。。。)

接着,我们在app下找到一个叫package.js(是不是很熟悉,没错,你在controller里头也见过同样的文件,所以,你可以发现,package.js就是整个框架的配置文件,而且是不同层面下都需要一个。)

package.js:

sumeru.packages(   'config',   'controller',   'model',   'library',   'jslib/jquery.js');

注意,前面4个是框架必须导入的库,最后一个才是我自行添加的。jslib就是刚才我在app下自行创建的文件夹

,当然,如果你喜欢你可以叫他jsFiles,这个纯属个人喜好。另外需要提及的是,如果你在里面要使用其他各种的JS框架库,你可以在后面继续添加jslib/xxx.js,也有一个一部到位的方法,就是直接改成jslib,那么,Clouda就会把整个文件夹加载进来,读取里面一个叫package.js(路径为:jslib/package.js),所以这个时候你要相应配置一下jslib/package.js,详细配置入下:


app/package.js:

sumeru.packages(   'config',   'controller',   'model',   'library',   'jslib');

app/libs/package.js:

sumeru.packages(   'jquery.js');


简而言之,如果你不想你的配置列表被配置得太长太难看(当你需要管理的模块结构文件非常大和非常多的时候!),你可以尝试使用以上的方式去配置每一个文件的依赖关系,这样,妈妈再也不用担心我的配置表太凌乱了:-)


还有一个问题需要提及一下,千万不要在package.js文件下写注释或者其他js代码,哪怕是console.log('加载文件');

我不太清楚是Nodejs上的约定还是Clouda在约定(我个人也是刚开始接触Nodejs),我也没见过其他nodejs的package.js配置文件存在这些。反正就是,千万别做这样的蠢事就对了,否则,出错了你也不知道是什么问题(因为这个绝对不是js文件这么简单)。


继续我们的RSS阅读器,回顾这个Controller/RSSreader.js控制器

getData Fn 开始:


var getData = function() {//这里负责获取并解释从路由器传递过来的参数(我们这里需要RSS网址)var argLength = env.arguments.length;var url = '';console.log('arg length -> '+argLength);for(var i=1;i<argLength;++i){var arg = env.arguments[i]if(arg=='http:'||arg=='https:')arg+='//';else if(i!=argLength-1)arg+='/';url+=arg;}console.log('url -> '+url);             //分析完之后我们要使用subscribe去做处理             //每个subscribe都要对应一个publishenv.subscribe('pubhtml', url , function(newsCollection){//console.log(ewsCollection.getData());            var obj = newsCollection.getData()[0];            //使用文档处理方法,返回一条压缩过的html代码            var content = processDoc(obj['body']);            //session与 block 进行数据绑定            session.bind('htmlBlock', {                'htmlContent' : content            });        });



通过env对象,可以获取arguments,arguments的大致内容是路由器匹配后的地址信息"RSS/xx/xxx/xx",

还是用/符号分割的每一个占一个位置,所形成的数组,而arguments[0]则被"RSS"所占用,所以这里我们从下标1开始索引到最后一个参数用来形成一个Url地址

(RSS阅读源的URL,比如:http://atalasii.com/rss 。在程序中的arguments获取处理则是:arguments[1]:'http',arguments[2]:'atalasii.com',arguments[3]:'rss')。

所以,我设计当程序完整被访问的时候,实际使用的形式是:http://localhost:8080/index.html/RSS/rss源URL地址

以上面的URL例子,则是:http://localhost:8080/index.html/RSS/http://atalasii.com/rss

这里的https://atalasii.com/rss就是完整的RSS阅读源地址,只需要加在RSS后面就可以了,路由器通过RSS匹配到后自动找到相应的控制器,而我们设定的控制器将解释后面的参数,形成合法的URL,稍后将介绍如何读取这个URL内容


subscribe / publish

Clouda提供subscribe(订阅)与publish(发布)的API,提供数据处理,也就是接着上文,我们获取了URL后要使用这套API进行数据获取和展示

env.subscribe('pubhtml', url , function(newsCollection){//console.log(ewsCollection.getData());            var obj = newsCollection.getData()[0];            //使用文档处理方法,返回一条压缩过的html代码            var content = processDoc(obj['body']);            //session与 block 进行数据绑定            session.bind('htmlBlock', {                'htmlContent' : content            });        });


上面的代码,做了一个简单的订阅服务,首先,url已经被拼接完成了,剩下的就是使用订阅服务,将url发到publish去处理。

Next step -> 我们创建一个publish去获取数据

publish主要用于作为获取后台数据库的数据,然后提供给subscribe,所以这两个API是成对使用的

不过在这里由于RSS里的内容并不存储在我们的数据中,而是一个外部的API,所以,这个时候我们在这里还要做一个外部数据的扩展,详情步骤如下:

在app下的publish目录里(如果没有请自行新建)创建一个pubhtml.js:

module.exports = function(fw){    fw.publish('html','pubhtml',function(url,callback){        var collection = this;        collection.extfind('feedContent',url,callback);    });}

这里的pubhtml文件的命名与控制器(RSSreader.js)里头的env.subscribe('pubhtml'...是一致的,意思是subscribe(订阅)名字叫(pubhtml)的publish(发布)

在pubhtml.js里头,里面的url,就是从RSSreader.js传递进来的参数,现在要在获取外部信息,所以我们使用了publish external


publish external 官方的解释就是实现了三方数据同步的方法,用来满足从三方网站/三方接口获取和同步数据的需求。


我们在同目录下再创建一个js文件 externalConfig.js:

/** * 获取第三方数据信息,由开发者自定义 */function runnable(){    var iconv = require('iconv-lite');    //{Object} config是所有三方publish配置的容器    var config = {};    config['feedContent'] = {        //{String} uniqueColumn为三方数据唯一标识        //uniqueColumn : "name",        //method:GET/POST,暂不支持PUT和DELETE方法,默认请求方式为GET        method:"POST",        //{Function} fetchUrl的参数就是订阅时发起的参数,返回值为pubext所抓取的url地址        fetchUrl : function(url){            console.log(url);            return url;//'http://segmentfault.com/feeds';        },        //{Function} resolve方法作用是将抓取回来的原始数据(originData)转化成为符合Model定义的数据(resolved)        resolve : function(originData){            console.log(originData);            var resolved = {head:'2',body:originData};            return resolved;        },        //{Number} fetchInterval为可选参数,用来指定抓取时间间隔,单位为ms        //fetchInterval : 60 * 1000,        //{Boolean} buffer为可选参数,值为true时表示获取原始Buffer,否则获取原始数据字符串        buffer : false    }    //最后需要声明此模块为归属为'external'    return {        type : 'external',        config : config    }}module.exports = runnable;

上述代码是改自官方API手册的代码,其中第10行就定义了这个external的名字"feedContent",然后根据publish的collection.extfind方法匹配名字和传递url参数

collection.extfind('feedContent',url,callback);


而这里定义的resolve方法取抓取url地址源的数据,并且通过简单的封装处理,返回给上层(publish -> Controler),所以最终发现Controler(RSSreader.js)里头的这段代码是如何处理这个被封装的对象:

env.subscribe('pubhtml', url , function(newsCollection){//console.log(ewsCollection.getData());            var obj = newsCollection.getData()[0];            //使用文档处理方法,返回一条压缩过的html代码            var content = processDoc(obj['body']);            //session与 block 进行数据绑定            session.bind('htmlBlock', {                'htmlContent' : content            });        });

最后,使用session对象(session对象是当前页面的会话对象,每一个打开该应用的都会有独立的session对象)来进行数据绑定联动更新,最后,这个应用就算完成了。

按照以上步骤创建好应用好,你只需要在浏览器输入:http://localhost:8080/index.html/RSS/http://atalasii.com/rss   就可以访问数据源是http://atalasii.com/rss的RSS信息,一个相对简陋的阅读器。

当然,你也可以启动debug模式,只需要将index.html改为debug.html,然后打开控制台(不知道如何呼出控制台的,请先面壁),你就可以看到各种调试信息,方便你开发应用!


最后公开这个小DEMO的源码Github地址:https://github.com/forfuns/Clouda_RSS_Reader

(注意:由于mongodb比较大无法上传到github,请无视mongodb下的所有东西,或者删除掉另行创建mongodb)


最后的最后 :-) 说下对使用这个框架的感受:

CloudaJs 是一个非常易用的NodeJs框架,正如官方所描述的一样可以实时更新数据,使用Socket实现零延迟;高兼容性,可以使用各种前端JS的框架(比如目前我使用的 jQuery),不需要入侵其他框架库代码;易用快速入门,语法精炼简单,API清晰,会JS你就可以前后端兼顾。配合百度自身搜索优势,一键托管还有SEO优化随手可得。


总体来说,是一个免费强大,居家旅行必备的轻应用框架。


2013-12-24 补充:

部署到BAE上,附带CSDN的RSS阅读地址,总体效果预览请猛击下面(界面什么的暂且无视吧,能阅读就好!)

http://onlinerssreader.duapp.com/index.html/RSS/http://www.csdn.net/article/rss_lastnews