• Archive by category "Javascript语言实践"
  • (Page 13)

Blog Archives

Nodejs与R跨平台通信

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-rserve-nodejs/

rserve-nodejs

前言

做web开发还没有用过Nodejs的同学,你们已经落后了。Nodejs是基于Javascript实现的一款后台程序开发平台,以我个人的体验开发效率比PHP还要高一些,完全异步加载性能一点也不落后,假以时日还有赶超趋势。

HTML5做为web前端大量使用Javascript,各种炫效果层出不穷。如果能把R语言的效果图,都用HTML5重新做渲染,并增加时时通信和用户交互,两种语言各取优势,必然产生惊为天人的效果。

长话短说,今天介绍 Nodejs与R跨平台通信

目录

  1. Nodejs简单介绍
  2. R语言配置环境
  3. Nodejs配置环境
  4. Nodejs与R跨平台通信

1. Nodejs简单介绍

Node.js是一个可以快速构建网络服务及应用的平台,基于Chrome’s JavaScript runtime,也就是说,实际上它是对GoogleV8引擎(应用于Google Chrome浏览器)进行了封装。V8引擎执行Javascript的速度非常快,性能非常好。Node对一些特殊用例进行了优化,提供了替代的API,使得V8在非浏览器环境下运行得更好。

2. R语言配置环境

本文中介绍的 Nodejs与R的跨平台通信,对于R语言的支持库是Rserve,通过Rserve提供一个R的TCP/IP的通信协议,实现Nodejs和R的通信。关于如何配置Rserve,请参考文章:Rserve与Java的跨平台通信

我已经在Linux配置好的Rserve环境,进程号9736,端口6311


~ ps -aux|grep Rserve
conan     9736  0.0  1.2 116288 25440 ?        Ss   13:11   0:01 /usr/lib/R/bin/Rserve --RS-enable-remote

~ netstat -nltp|grep Rserve
tcp        0      0 0.0.0.0:6311            0.0.0.0:*               LISTEN      9736/Rserve

3. Nodejs配置环境

对于Nodejs环境,也比较简单,以express3库作为基础web框架,rio是让Nodejs与Rserve通信的依赖库。如果是Nodejs的新手从头学习,请参考系列文章:从零开始nodejs系列文章,如果仅仅搭建一个Nodejs测试环境,请参考文章:准备Nodejs开发环境Ubuntu

现在我们已创建好了Express3的项目(开发环境Win7)

项目目录:D:\workspace\project\investment\webui


~ D:\workspace\project\investment\webui>ls
README.md  app.js  models  node-rio-dump.bin  node_modules  package.json  public  routes  views

安装rio库


~ D:\workspace\project\investment\webui>npm install rio
npm http GET https://registry.npmjs.org/rio
npm http 200 https://registry.npmjs.org/rio
npm http GET https://registry.npmjs.org/rio/-/rio-0.9.0.tgz
npm http 200 https://registry.npmjs.org/rio/-/rio-0.9.0.tgz
npm http GET https://registry.npmjs.org/hexy
npm http GET https://registry.npmjs.org/binary
npm http 200 https://registry.npmjs.org/binary
npm http 200 https://registry.npmjs.org/hexy
npm http GET https://registry.npmjs.org/binary/-/binary-0.3.0.tgz
npm http GET https://registry.npmjs.org/hexy/-/hexy-0.2.5.tgz
npm http 200 https://registry.npmjs.org/hexy/-/hexy-0.2.5.tgz
npm http 200 https://registry.npmjs.org/binary/-/binary-0.3.0.tgz
npm http GET https://registry.npmjs.org/chainsaw
npm http GET https://registry.npmjs.org/buffers
npm http 200 https://registry.npmjs.org/buffers
npm http 200 https://registry.npmjs.org/chainsaw
npm http GET https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz
npm http GET https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz
npm http 200 https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz
npm http 200 https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz
npm http GET https://registry.npmjs.org/traverse
npm http 200 https://registry.npmjs.org/traverse
npm http GET https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz
npm http 200 https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz
rio@0.9.0 node_modules\rio
├── hexy@0.2.5
└── binary@0.3.0 (buffers@0.1.1, chainsaw@0.1.0)

4. Nodejs与R跨平台通信

下面我们开始写程序,来实现跨平台的通信。

在app.js配置文件中,增加一个路由路径


~ vi app.js
//代码有省略
var vis = require('./routes/vis')
app.get('/vis/rio',vis.rio);

在路由目录/routes增加一个路由文件vis.js


~ vi /routes/vis.js

var rio = require("rio");
exports.rio = function(req, res){
	options = {
		host : "192.168.1.201",
		port : 6311,
        callback: function (err, val) {
            if (!err) {
            	console.log("RETURN:"+val);
            	return res.send({'success':true,'res':val});
            } else {
            	console.log("ERROR:Rserve call failed")
            	return res.send({'success':false});
            }
        },
    }
    rio.enableDebug(true);//开启调试模式
    rio.evaluate("pi / 2 * 2 * 2",options);//运行R代码
};

在上面代码中,我们实现了rio与rserve的远程连接。以R的命令(pi / 2 * 2 * 2)作为参数,传给Rserve。通过callback的方法,获得R的返回值。

在浏览器中测试:
http://localhost:3000/vis/rio
在浏览器中返回:是一个json格式的对象

{
  "success": true,
  "res": 6.283185307179586
}

命令行日志


Connected to Rserve
Supported capabilities --------------

Sending command to Rserve
00000000: 0300 0000 1400 0000 0000 0000 0000 0000  ................
00000010: 0410 0000 7069 202f 2032 202a 2032 202a  ....pi./.2.*.2.*
00000020: 2032 0001                                .2..

Data packet
00000000: 2108 0000 182d 4454 fb21 1940            !....-DT{!.@

Type SEXP 33
Response value: 6.283185307179586
RETURN:6.283185307179586
GET /vis/rio 200 33ms - 49b
Disconnected from Rserve
Closed from Rserve

我可以看到nodejs与Rserve的通信情况,Response value: 6.283185307179586,与页面上面是一致的。

接下来,我们改一下R的运行命令:
rnorm(10),取10个符合N(0,1)正态分布的随机数


rio.evaluate("rnorm(10)",options);//运行R代码

浏览器返回结果


{
  "success": true,
  "res": [
    -0.011531884725262991,
    0.5106443501593562,
    -0.05216533321965309,
    1.9221980152236238,
    0.5205238122633465,
    -0.3275367539102907,
    -0.06588102930129405,
    1.5410418730008988,
    1.308169913050071,
    0.005044179478212583
  ]
}

命令行日志


Connected to Rserve
Supported capabilities --------------

Sending command to Rserve
00000000: 0300 0000 1000 0000 0000 0000 0000 0000  ................
00000010: 040c 0000 726e 6f72 6d28 3130 2900 0101  ....rnorm(10)...

Data packet
00000000: 2150 0000 f6ca 0c5e 079e 87bf 9b4a fad1  !P..vJ.^...?.JzQ
00000010: 3257 e03f eda2 5320 6ab5 aabf 2b25 bdb4  2W`?m"S.j5*?+%=4
00000020: 52c1 fe3f ebba ce8d 21a8 e03f bc17 92b7  RA~?k:N.!(`?<..7
00000030: 5cf6 d4bf ca9f 4642 94dd b0bf 1be3 e485  \vT?J.FB.]0?.cd.
00000040: 1ba8 f83f 5a94 2293 43ee f43f 1724 4e9e  .(x?Z.".Cnt?.$N.
00000050: 34a9 743f                                4)t?

Type SEXP 33
Response value: -0.011531884725262991,0.5106443501593562,-0.05216533321965309,1.9221980152236238,0.5205238122633465,-0.3
275367539102907,-0.06588102930129405,1.5410418730008988,1.308169913050071,0.005044179478212583
RETURN:-0.011531884725262991,0.5106443501593562,-0.05216533321965309,1.9221980152236238,0.5205238122633465,-0.3275367539
102907,-0.06588102930129405,1.5410418730008988,1.308169913050071,0.005044179478212583
GET /vis/rio 200 30ms - 285b
Disconnected from Rserve
Closed from Rserve

我们实现了Nodejs与R跨平台通信,有点感觉像打通了中国功夫的“任督二脉”,从此以后,成为一代高手。

转载请注明出处:
http://blog.fens.me/r-rserve-nodejs/

打赏作者

nodejs分页设计配合bootstrap-paginator

从零开始nodejs系列文章

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者
张丹(Conan), 程序员Java,R,PHP,Javascript
weibo:@Conan_Z
blog: http://blog.fens.me
email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-bootstrap-paginator/

前言

分页功能是查询的必备功能,比如我要查询一个多于1000条记录的结果集。如果一次全部展示,不仅浪费带宽,增长等待时间,用户看到这么多的数据也会觉得的头疼。但是有了分页功能,可以根据用户的习惯,一页一页的处理少量的数据,展示少量的数据,就像是在看书一样的。

分页功能非常实用,但是实现起来也稍有复杂。不仅要考虑到前端的展示和传值问题,还要考虑后端面向数据的查询语句。不过我也发现了前端和后端对应的解决的方案。前端程序可以通过bootstrap-paginator项目来封装,而后端我是自己实现的。本来是准备使用mongoose-paginate项目,但他的设计过于简单,而且与bootstrap-paginator的一些传参习惯不符,自已实现其实更好控制。

page

目录

  1. 分页前端雏形bootstrap-paginator
  2. 分页后端查询mongoose
  3. 分页结果返回页面(后端->前端)
  4. 分页查询参数传递(前端->后端)
  5. 分页完整展现

 

1. 分页前端雏形bootstrap-paginator

下载bootstrap-paginator:下载地址
解压后,把bootstrap-paginator.min.js文件复制到public/js的目录

如果你的项目,已经配置了bootstrap, jquery。 那么你只需要在用到分页的网页上增加一行js包的引用就可以了。

~ vi view/admin/moive.html
<html>
<head>
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen" />
<script type="text/javascript" src="/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/js/bootstrap-paginator.min.js"></script>
</head>
<body>
<!-- 代码片断 查询表单 -->
<form method="GET">
...
</form>

<!-- 代码片段 分页控件 -->
<div class="span12">
<div id="page1"></div>
</div>

<!-- 代码片段 查询结果 -->
<div class="span12">
<table class="table table-hover table-striped">
...
</table>
</div>

<!-- 代码片段 -->
<script type="text/javascript">
$(function(){

//分页功能
var options = {
currentPage:2,
totalPages:5,
numberOfPages:5
}
$('#page1').bootstrapPaginator(options);

})
</script>

</body>
</html>

显示效果:

p2

2. 分页后端查询mongoose

使用mongoose访问mongodb,在 Mongoose使用案例–让JSON数据直接入库MongoDB 一文中已经讲过。

我们构建分布查询的DAO。

  • 这里Movie是model类型,没有用到entity。直接通过model做的分页查询。
  • 分页查询是二步查询,第一步查询结果集数据,第二步查询总记录
  • 通过skip,limit进行分页。(关于skip的效率问题,10W以下的记录,skip性能是可以接受的,10w以上的记录需要根据排序的字段,通过索引定位查询,这个概念以后再讲。)
  • 排序功能默认用插入时间倒叙:sort(‘-create_date’)

查询参数:

  • q,查询条件
  • col,数据返回字段
  • pageNumber,当前是第几页,如果不存在默认为第1页
  • resultsPerPage,每页多少条记录

分页的返回值

  • null:空错误,因为错误已经通过if处理了
  • pageCount:一共有多少页
  • results:数据结果集

~ vi model/Movie.js

var Movie = mongodb.mongoose.model("Movie", MovieSchema);
var MovieDAO = function(){};

//代码片段

MovieDAO.prototype.findPagination = function(obj,callback) {
  var q=obj.search||{}
  var col=obj.columns;

  var pageNumber=obj.page.num||1;
  var resultsPerPage=obj.page.limit||10;

  var skipFrom = (pageNumber * resultsPerPage) - resultsPerPage;
  var query = Movie.find(q,col).sort('-create_date').skip(skipFrom).limit(resultsPerPage);

  query.exec(function(error, results) {
    if (error) {
      callback(error, null, null);
    } else {
      Movie.count(q, function(error, count) {
        if (error) {
          callback(error, null, null);
        } else {
          var pageCount = Math.ceil(count / resultsPerPage);
          callback(null, pageCount, results);
        }
      });
    }
  });
}

 

3. 分页结果返回页面(后端->前端)

传参数到页面:page对象

  • limit:5,每页限制5条记录
  • num:1,查询的页面
  • pageCount,一共有多少页
  • size,当前页面有多少条记录
  • numberOf,分页用几个标签显示

~ vi routes/moive.js

//代码片段
exports.movie = function(req, res) {
var search={};
var page={limit:5,num:1};

//查看哪页
if(req.query.p){
page['num']=req.query.p<1?1:req.query.p;
}

var model = {
search:search,
columns:'name alias director publish images.coverSmall create_date type deploy',
page:page
};

Movie.findPagination(model,function(err, pageCount, list){
page['pageCount']=pageCount;
page['size']=list.length;
page['numberOf']=pageCount>5?5:pageCount;

return res.render('admin/movie', {
title:'电影|管理|moive.me',
page:'admin',nav:'admin.movie',
movieList:list,
page:page
});
});
}

4. 分页查询参数传递(前端->后端)

前端向后端:参数传递过程

  • 通过javascript,从页面向控制器传参数p.
  • 通过composeUrlParams函数,封装原表单的查询参数
  • 通过pageUrl函数,拼接带分布的url请求

后端向前端:参数传递过程

  • 如果page1的div增加自定义属性
  • 在页面渲染时,通过js解析div增加自定义属性,赋值给bootstrap-paginator控件
~ vi view/admin/moive.html

//修改分页的div,增加自定义的属性
<div class="span12">
<div id="page1" pageCount="<%=page.pageCount%>" pageNum="<%=page.num %>" pageSize="<%=page.size%>" pageLimit="<%=page.limit%>" numberOfPages="<%=page.numberOf%>"></div>

<!-- 代码片段 -->
<script type="text/javascript">
$(function(){

//获得浏览器参数
$.extend({
getUrlVars: function(){
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++){
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
},
getUrlVar: function(name){
return $.getUrlVars()[name];
}
});

//封装浏览器参数
var composeUrlParams=function(){
var param='';
$.each($.getUrlVars(), function(i, item) {
if(item!='p'){
var val=$.getUrlVar(item);
if(val) param += "&" + item+"="+val;
}
});
return param;
}

//分页功能
var page=$('#page1');
var options = {
currentPage:page.attr('pageNum'),
totalPages:page.attr('pageCount'),
numberOfPages:page.attr('numberOfPages'),
pageUrl: function(type, page, current){
return "/admin/movie?"+composeUrlParams()+"&p="+page;
}
}
$('#page1').bootstrapPaginator(options);
})
</script>

5. 分页完整展现

p1

 

分页功能可能实现起来稍有复杂,如果可以完整地封装成一个控件,就会变得非常简单了。不知道是否已经有人做好了这个控件。

如果有时间,我可能也会写一下。希望能帮助到对分页还陌生的朋友。

 

转载请注明出处:
http://blog.fens.me/nodejs-bootstrap-paginator/

打赏作者

Nodejs对MongoDB模糊查询

从零开始nodejs系列文章

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者
张丹(Conan), 程序员Java,R,PHP,Javascript
weibo:@Conan_Z
blog: http://blog.fens.me
email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-mongodb-regexp

reg-title

前言

模糊查询是数据库的基本操作之一,实现对给定的字符串是否与指定的模式进行匹配。如果字符完全匹配,可以用=等号表示,如果部分匹配可认为是一种模糊查询。在关系型数据中,通过SQL使用like ‘%fens%’的语法。那么在mongodb中我们应该如何实现模糊查询的效果呢。

目录

  1. mongodb模糊查询
  2. nodejs通过mongoose的模糊查询

1. mongodb模糊查询

我们打开mongodb,以name文字字段进行测试。

精确查询
当{‘name’:’未来警察’}时,精确匹配到一条记录。


db.movies.find({'name':'未来警察'})

reg

模糊查询
{‘name’:/未来/},匹配到了多条记录。


db.movies.find({'name':/未来/})

reg2

MongoDB的模糊查询,其实是正则查询的一种。
注:在关系型数据中,单独有一个关键字like做模糊查询,如果不用like,也可以在关系型数据中使用正则查询。

MongoDB官方介绍:http://docs.mongodb.org/manual/reference/operator/regex/

官方举例:
db.collection.find( { field: /acme.*corp/i } );
db.collection.find( { field: { $regex: 'acme.*corp', $options: 'i' } } );

2. nodejs通过mongoose的模糊查询

希望实现的效果:
reg3

下面说说如何用mongoose进行模糊查询。

使用mongoose访问mongodb,在 Mongoose使用案例–让JSON数据直接入库MongoDB 一文中已经讲过。

我们对Movie建模,并构造dao层。

查询所有电影


MovieDAO.prototype.findByName = function(query, callback) {
  Movie.findOne(query, function(err, obj){
    callback(err, obj);
  });
};

通过传入query对象,就可以进行查询。

接下来,构造query对象


//代码片断
exports.movie = function(req, res) {
  var query={};
  if(req.query.m2) {
    query['name']=new RegExp(req.query.m2);//模糊查询参数
  }

  Movie.findByName (query,function(err, list){
    return res.render('admin/movie', {movieList:list});
  });
}

请注意,刚才我们已经分析了MongoDB的的模糊查询是通过正则表达式实现的,对应mongodb中,可以直接使用 ‘/../’ 斜杠。
但是在nodejs中,必须要使用RegExp,来构建正则表达式对象。

其实很简单,一层窗户纸。知道了实现原理,一切都变得很容易。

转载请注明出处:
http://blog.fens.me/nodejs-mongodb-regexp

打赏作者

Nodejs配合bootstrap-select下拉列表

从零开始nodejs系列文章

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者
张丹(Conan), 程序员Java,R,PHP,Javascript
weibo:@Conan_Z
blog: http://blog.fens.me
email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-bootstrap-select/

前言

网页里的下位列表,英文名drop down list,几乎所有网站都会用到这个组件。bootstrap已经设计了一个下拉列表的基本样式,在表单中展示已经够用了,但如果我们希望有更多一些的功能,不妨学一下Bootstrap-select,github项目地址 ,官方demo

 

目录

  1. 功能需求列表
  2. 代码实现
  3. 使用bootstrap-select实现需求

 

我将通过一个例子进行演示

dropdwon1

1. 功能需求

如图所示,表单中“类型”使用下拉列表

有如下的显示要求:

  • 默认显示 “请选择”
  • 默认值是空
  • 单选下拉列表
  • 下拉后选中的行,结尾以“√”标识
  • 下拉列表长度为5行,多于5行的用滚动条显示
  • 通过nodejs传参数设置默认值

 

2. 代码实现

使用bootstrap

nodejs中使用bootstrap,在 Nodejs开发框架Express3.0开发手记–从零开始 一文中已经有介绍。

引入bootstrap-select类库

下载类库:https://github.com/silviomoreto/bootstrap-select/zipball/master

解压后,使用下面2个文件:
bootstrap-select.min.js,放到public/js目录
bootstrap-select.min.css,放到public/css目录

在view/admin/moive.html中引用这两个文件,(代码片段)

~ vi view/admin/moive.html
<html>
<head>
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen" />
<link href="/css/bootstrap-select.min.css" rel="stylesheet" media="screen" />

<script type="text/javascript" src="/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/js/bootstrap-select.min.js"></script>
</head>
<body>
<!-- 代码片断 -->
<form class="form-horizontal well" method="GET">
<select name="type" class="selectpicker show-tick" data-size="5" value="<%=search.type||''%>">
<option></option>
<option>科幻</option>
<option>剧情</option>
<option>犯罪</option>
<option>西部</option>
<option>爱情</option>
</select>
</form>

<!-- 代码片段 -->
<script type="text/javascript">
$(function(){

//下拉菜单
$('.selectpicker').selectpicker({noneSelectedText:'请选择'});
$('.selectpicker').selectpicker('val',$('.selectpicker').attr('value'));

})
</script>

</body>
</html>

3. 使用bootstrap-select实现需求

通过select标签实现下拉列表

初始化样式:
通过class=”selectpicker”,设置bootstrap-select的样式。
通过$(‘.selectpicker’).selectpicker(),启动js渲染

默认显示 “请选择”
$('.selectpicker').selectpicker({noneSelectedText:'请选择'});

默认值是空
<option></option>

单选下拉列表
无特别代码。
多选下拉列表,增加multiple属性
<select class="selectpicker" multiple >

下拉后选中的行,结尾以“√”标识
增加show-tick的css显示类型
<select class="selectpicker show-tick" >

下拉列表长度为5行,多于5行的用滚动条显示
增加data-size=”5″的属性
<select class="selectpicker" data-size="5" >

通过nodejs传参数设置默认值
增加value属性,获得nodejs的传参

<select name="type" class="selectpicker show-tick" data-size="5" value="<%=search.type||''%>">

再通过javascript前端赋值

$('.selectpicker').selectpicker('val',$('.selectpicker').attr('value'));

 

实现下拉列表的需求功能:

dropdwon2

转载请注明出处:
http://blog.fens.me/nodejs-bootstrap-select/

打赏作者

upstart封装nodejs应用为系统服务

从零开始nodejs系列文章

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

张丹(Conan), 程序员Java,R,PHP,Javascript
weibo:@Conan_Z
blog: http://blog.fens.me
email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/linux-upstart-nodejs/

upstart-nodejs

 

本文将介绍封装nodejs应用为系统服务,应用会像一个守护程序一样,被操作系统所管理。

文章目录:

  1. nodejs应用介绍
  2. upstart任务脚本
  3. nodejs应用管理

1. nodejs应用介绍

终于要把nodejs的应用程序部署上线了, node和npm在ubuntu下安装,请参考:准备Nodejs开发环境Ubuntu

把源代码通过git复制到目录下面
/root/deploy/movie
然后搞命令:


~ cd /root/deploy/movie
node ./app.js

上面的方式,nodejs程序会在当前的console界面中运行,一旦console结束,应用也会停止。我们改一下命令,让程序在后台运行


~ node ./app.js &
[1] 21333
[2013-06-21 09:38:30.696] [INFO] console - Start App: http://moive.me
[2013-06-21 09:38:30.700] [INFO] console - Express server listening on port 3000

这样程序就就在后台启动了。进程正常运行着,我也不用做太多的事情。

如果我想停止这个程序,怎么办呢? 找到nodejs的系统进程,再杀死。


~ ps -aux|grep node
root     21333  0.6  3.7 909200 38292 pts/0    Sl   09:38   0:00 node app.js
~ kill -9 21333  

直接暴力解决。如果能像系统服务一样,来启动和关闭nodejs应用,多好啊!下面就通过upstart来完成把nodejs应用封装为系统服务。

2. upstart任务脚本

upstart的使用在 upstart把应用封装成系统服务 一文中已经介绍过了。


~ vi /etc/init/nodejs-moive.conf

description "node.js moive.me"
author "bsspirit <http://blog.fens.me>"

start on startup
stop on shutdown

script
    export HOME="/root/deploy/movie"
    echo $$ > /var/run/moiveme.pid
    export NODE_ENV=production
    exec /usr/bin/node /root/deploy/movie/server.js

    #日志输出
    #exec /usr/bin/node /root/deploy/movie/server.js >> /var/log/moiveme.log 2>&1
end script

pre-start script
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Starting" >> /var/log/moiveme.log
end script

pre-stop script
    rm /var/run/moiveme.pid
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Stopping" >> /var/log/moiveme.log
end script

3. nodejs应用管理

启动nodejs-moive应用,进程ID:21257


~ start nodejs-moive
nodejs-moive start/running, process 21257

~ tail -f /var/log/moiveme.log
[2013-06-21T09:21:17.122Z] (moive.me) Starting

~ ps aux|grep node
root     21257  8.0  3.7 909204 37824 ?        Ssl  09:21   0:00 /usr/bin/node /root/deploy/movie/server.js

查看运行状态, 进程21257正常运行


~ status nodejs-moive
nodejs-moive start/running, process 21257

杀死nodejs应用进程21257,通过upstart管理,nodejs-moive应用会自动重启


~ kill -9 21257

#自动重启日志
~ tail -f /var/log/moiveme.log
[2013-06-21T09:21:33.662Z] (moive.me) Starting

#查看系统进程,发现进行ID变了
~ ps -aux|grep node
root     21280  9.1  3.7 909204 37704 ?        Ssl  09:21   0:00 /usr/bin/node /root/deploy/movie/server.js

#查看进程状态,进程ID确实变了,而且是自动完成的
~ status nodejs-moive
nodejs-moive start/running, process 21280

这样很方便地我们可以通过upstart,以系统服务的方式管理nodejs应用。运维起来会很容易!!

 

转载请注明出处:
http://blog.fens.me/linux-upstart-nodejs/

打赏作者