Nodejs

linux下安装nodejs

月盾

此文过旧,请参阅linux安装nodejs——快捷版

首先下载nodejs压缩文件node-v4.4.4-linux-x64.tar.xz,先解压文件, > xz -d node-v4.4.4-linux-x64.tar.xz解压为tar格式文件,再通过tar命令解压 > tar -xvf node-v4.4.4-linux-x64.tar 可以将解压后的文件夹移动到自己的软件安装文件夹下,比如:/usr/local下,因为nodejs的版本更新太快,每次更新都这么移动文件夹太麻烦,所以还是改成一个通用的名字,就叫node,执行命令这样: mv /home/huo/Download/node-v4.4.4-linux-x64 /usr/local/node 为了能够全局执行node和npm命令,需要建立软链接到可执行目录下,执行命令: echo $PATH 可以看到:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin是linux全局执行目录,所以就选择在/usr/local/bin下建立软链接吧。

ln -s /usr/local/node/bin/npm /usr/local/bin/npm

这样就可以在任意目录下执行node和npm命令了,不过这样还没结束,使用npm全局安装包后,在命令行里执行会找不到命令,因为npm全局安装目录在node安装目录,也就是安装在了/usr/local/node/lib/node_modules目录下,所以还需要将这个目录添加的$PATH变量中,sudo vim /etc/profile在文件最下边添加export PATH="/usr/local/node/bin:$PATH",此处的路径/usr/local/node/bin并不是上面说的/usr/local/node/lib/node_modules目录,因为npm全局安装以后会在node安装目录下的bin文件夹中建立软链接,直接在$PATH中添加npm的全局安装目录是无法找到可执行文件的。

升级node版本 可以通过全局安装n工具来升级 npm install -g n,或者nvm工具 或者就是直接下载新的tar文件覆盖升级 cp -Rv node-v8.11.3-linux-x64/* /home/yuedun/software/nodejs/

用java的思想方式写javascript

月盾

javascript和java有相似之处也有很大区别,对于初学者来说很容易被名称迷惑,其实当初javascript就是借着java的顺风车进行推广的。

由于javascript是动态语言,java是静态语言,所以两者在编写方式上有很大区别,主要是因为javascript没有类的概念,在ES6标准发布之前要构造一个对象需要用new关键字实例化一个function或者直接使用对象字面量。不过ES6标准的发布,使得javascript也可像java一样声明类了。

在使用nodejs开发大型应用时需要到类的概念来封装一个复杂的逻辑,我们可以从现在开始逐步使用ES6开发,但是基于现有的支持环境,很多时候还得用ES5编写代码,那么这时候怎么来抽象一个类和实例化对象?

以Java的思想方式来编写JavaScript,首先是一个构造函数:

function Person(name, age){
	this.name = name;
	this.age = age;
}

这就像是Java的构造函数,可以new一个对象出来

var tom = new Person("Tom",12);

构造函数的用处是在创建对象的时候就初始化了属性的值,不用再单独赋值,不需要再像这样赋值:

var tom = new Person();

tom.name = "Tom";
tom.age = 13;

有了构造函数,还要有普通函数:

tom.sayHello = function(){

	console.log("my name is "+this.name);//my name is Tom

}

接下来是静态函数:静态方法就是由类名直接调用的的方法,不需要new一个对象

function Person(name, age){
	this.name = name;

	this.age = age;

}

Person.getAge = function(){

	console.log(this.age);

}

Person.age = 12;

Person.getAge();//类似于Java中的静态方法只能使用静态变量,所以此处也需要一个静态age

至于普通函数与静态函数有什么区别?区别就在于静态函数会一开始就加载到内存中,当然就比较占用内存了,普通函数是在new以后才被初始化,函数使用完就释放内存。

sequelizejs删除对象属性

月盾

js中有个delete操作符可以删除对象的属性,比如下面代码:

//objtest对象有个prop属性

var objtest = {

  prop: 'delete me'

};

//或者这么声明的对象

var objtest = new Array();

objtest['prop'] = 'delete me';

//删除属性'prop':

delete objtest.prop;

//或者

delete objtest['prop'];

//还可以删除任意变量

var numb = 17;

delete numb;

但是在nodejs项目中使用了sequelizejs来读取数据,如果也有想删除的属性,直接使用delete是删不掉的,比如有这样的数据结构:

var user = {
	name: '鸣人',
	age: 16,
	gender: '男',
	friends: [{
		name: '小樱',
		age: 16,
		gender: '女',
		friends: [{
			name: '井野',
			age: 16,
			gender: '女'
		}]
	},
	{
		name: '佐助',
		age: 16,
		gender: '男'
	}]
}

鸣人有小樱和佐助两个朋友,小樱有井野一个朋友,小樱的朋友也可以当做鸣人的朋友,现在想把井野也提出来并列到鸣人的朋友列表里,这样做很容易,但是既然提出来了就不需要小樱的朋友列表了,应该删掉。但是用delete user.friends[0].friends这样的方法是删不掉的。可能的是sequelize对象的属性是放在dataValues对象下面的,不能直接删除。

据我debug观察,虽然有直接属性,但是sequelize提供了getDataValue方法来获取属性值,获取到的值应该是dataValues下面的。所以,就算即使用delete删掉了直接属性还是能获取到。

但是还是有办法的,可以这样删除

user.getDataValue('friends')[0].setDataValue('friends', undefined)

就是将属性设置为undefined,查询的时候就没有小樱的friends了。

使用sublime开发node.js快速跳转到变量函数声明处

月盾

开发中最常用的操作之一就是快速跳转到变量,方法声明处,比如在eclipse中按住Ctrl键鼠标点击变量或方法就能跳转到对应的位置或文件中,开发nodejs程序当然也需要这样的功能,比较强大的开发工具有webstorm,也是支持这种操作的。不过webstorm太占内存,4G的内存下总是提示内存不足,需要关闭占用内存程序,而首当其冲的就是webstorm,所以最近试了试另一款被大家熟知和推荐的开发神器sublime。虽然sublime是个文本编辑器,还不能算的上IDE,不过它可以安装各种插件来丰富功能,最重要的是它占用内存少,速度快。

所以,我要介绍的是在ST下如何做到跳转到变量或方法声明处。

首先在uses.js文件中有一个函数

//我是一个测试方法

router.get("/commeHere", function(req, res) {

});

然后我要从其他文件中跳转到这个函数。先关掉这个文件,打开其他文件。

st2.jpg

可以双击或鼠标选中commeHere这个关键词(才发现单词打错了),键盘按下Ctrl+shift+F就会出现类似搜索框,选中的关键字会填充到find框中,需要手动选择where框,选择Add Open Folders,文本框中填充的就是,然后回车就可以了,很快就会搜索出我们需要的关键字所在的文件。

双击就可以跳转到对应的文件和行上。

当然,不可能像eclipse中那么方便,但其实只有两步操作,第一ctrl+shift+F搜索关键字,第二双击搜索结果跳转到对应文件位置。如果你习惯使用ST的话肯定很满足这样的设计,根本不会觉得繁琐。

windows下使用脚本快速启动nodejs服务

月盾

每次启动node服务都要先打开cmd命令行,或者在win8下先打开文件资源管理器>文件>打开命令提示符,然后执行node命令,这样的过程真的很烦人,当然需要一个简单粗暴的方式启动了,就像用bat文件双击启动。
首先,建一个空白文件,输入以下内容:

E:  
cd E:\\NodejsWorkSpace\\app-node  
nodemon ./bin/www

就像我们平时要依次输入这些内容一样,不过还有更简单的方式:

E: && cd E:\NodejsWorkSpace\app-node && nodemon ./bin/www

使用&符号连接各个命令也可以

pm2在线监控

月盾

先来一张效果图:

](https://hopefully-img.yuedun.wang/172722906.png)

由图可以看出,监控内容有CPU,内存使用,系统bug,以及代码更新和重启服务,还有更多功能,比如bug邮件提醒功能。

使用方法很简单,几乎是一条命令搞定,首先打开https://app.keymetrics.io/#/

注册登录以后应该可以看到下图命令提示,在服务器中执行第一条命令,需要带后面的machine name

可能会失败,多试几次就可以了。然后再web页面会自动出现服务器状况。

使用nodemailer发送邮件

月盾
var nodemailer = require("nodemailer");

var transporter = nodemailer.createTransport({

	service: "gmail",

	auth: {

		user: "youname@gmail.com",

		pass: "password"

	}

});

transporter.sendMail({

	from: "youname@gmail.com",

	to: "username@qq.com",

	subject: "hello",

	text: "hello world!"

});

这是一个最基本的邮件发送程序,邮件服务商有以下:

  • “1und1”
  • “AOL”
  • “DebugMail.io”
  • “DynectEmail”
  • “FastMail”
  • “GandiMail”
  • “Gmail”
  • “Godaddy”
  • “GodaddyAsia”
  • “GodaddyEurope”
  • “hot.ee”
  • “Hotmail”
  • “iCloud”
  • “mail.ee”
  • “Mail.ru”
  • “Mailgun”
  • “Mailjet”
  • “Mandrill”
  • “Naver”
  • “Postmark”
  • “QQ”
  • “QQex”
  • “SendCloud”
  • “SendGrid”
  • “SES”
  • “Sparkpost”
  • “Yahoo”
  • “Yandex”
  • “Zoho”

sequelizejs中where条件与order排序的使用

月盾

最基本的where条件:

Post.findAll({
    where: {
        authorId: 2
    }
});
// SELECT \* FROM post WHERE authorId = 2

Post.findAll({
    where: {
        authorId: 12,
        status: active
    }
});

// SELECT \* FROM post WHERE authorId = 12 AND status = 'active';

Post.destroy({
    where: {
        status: 'inactive'
    }
});
// DELETE FROM post WHERE status = 'inactive';

Post.update({
    updatedAt: null,
},
{
    where: {
        deletedAt: {
            $ne: null
        }
    }
});

// UPDATE post SET updatedAt = null WHERE deletedAt NOT NULL;

如果涉及到or的使用,sequelize也提供了很好的解决方案

sequelize定义实体对象

月盾

sequelize定义实体对象

var sequelize = require("../utils/sequelizeDB");//连接数据库 var Sequelize = require("sequelize"); var User = sequelize.define("User", {  
user_id:{ type: Sequelize.STRING, primaryKey: true},  
name: Sequelize.STRING,  
phone: Sequelize.STRING,  
create_date: Sequelize.DATE,  
update_date: Sequelize.DATE  
}, {  
freezeTableName: true, // 默认false修改表名为复数,true不修改表名,与数据库表名同步  
tableName: "user",  
timestamps: false  
});

define函数的第一个参数’User’就是定义一个实体对象,名称不必与数据库表名一致,只是为了确定该对象没有重复 { type: Sequelize.STRING, primaryKey: true}将属性作为主键 freezeTableName禁用修改表名;默认情况下,sequelize会自动将模型名称(第一个参数定义‘User’)为复数。值为ture时不修改 tableName数据库表名 timestamps是否自动添加时间戳createAt,updateAt

node.js作为微信接口服务器

月盾

前端时间用node改写了下去年用Java练习时写的微信接口,可能是因为微信接口看的多了更加熟悉了,也可能是node开发更快速,反正不到一小时就搞定了微信token的验证,放到博客项目中,新增了一个URL请求,在微信公众平台上测试了下,没想到调试两三次就通过了,想当初用Java测试时各种问题不断。想起来可惜的是去年Java版的微信接口做的自定义菜单,自动回复等功能,由于BAE收费的缘故就废掉了。

/**  
 * Created by huopanpan on 2014/10/10.  
 */  
var crypto = require("crypto");  
/**  
 * 验证token  
 * @param req  
 * @param res  
 */  
function validateToken(req, res) {  
    var query = req.query;  
    var signature = query.signature;//微信服务器加密字符串  
    var echostr = query.echostr;//随机字符串  
    var timestamp = query["timestamp"];//时间戳  
    var nonce = query.nonce;//nonce  
    var oriArray = new Array();  
    oriArray[0] = nonce;  
    oriArray[1] = timestamp;  
    oriArray[2] = "hale";//token  
    oriArray.sort();  
    var original = oriArray[0]+oriArray[1]+oriArray[2];  
    console.log("Original Str:"+original);  
    console.log("signature:"+signature);  
    var scyptoString = sha1(original);//将三个参数拼接加密字符串,并与服务器发送的字符串对比  
    if (signature == scyptoString) {  
        res.send(echostr);  
    }  
    else {  
        res.send("Bad Token!");  
    }  
}

/**  
 * sha1加密  
 * @param str  
 * @returns {*}  
 */  
function sha1(str) {  
    var md5sum = crypto.createHash("sha1");  
    md5sum.update(str);  
    str = md5sum.digest("hex");  
    return str;  
}  
/**  
 * 重新获取access_token  
 * @type {validateToken}  
 */  
function getAccessToken(){  
    var appid = "";  
    var appsecret = "";  
    var url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=fdgf&secret=dfdsgfrf";

}  
exports.validateToken = validateToken;