Node.js 7.0发布之前,写一篇关于express的文章
项目创建
使用express-generator
- 使用npm install express-generator -g
代码修改自动重启
使用nodemon
- nodemon ./bin/www
全局设置
//加载配置项
global.Config = require(path.resolve(Root, './config/config'));
//通用方法(设置为全局对象,方便调用)
global.F = require(path.resolve(Root, './common/funcs'));
//socket事件方法
global.Socket = require(path.resolve(Root, './socket/socket'));
//加载所有的数据库model
global.M = {};
//model存储路径 (暂时不支持二级目录)
var modelsPath = path.resolve(Root, 'models');
fs.readdirSync(modelsPath).forEach(function (name) {
if (path.extname(name) !== '') {
name = path.basename(name, '.js');
M[name] = require(path.resolve(modelsPath,name));
}
});
使用co、Promise(bluebird)进行异步处理
定义通用方法run实行Promise,并抛出错误
let run = (fn,next) =>{
co(fn).catch((err) => {
next(err);
});
};
通用方法列表 (大部分抄袭thinkjs)
module.exports = {
run:run,
promisify:promisify,
camelCase:camelCase,
defer:defer,
Class:Class,
extend:extend,
isClass:isClass,
isBoolean:isBoolean,
isNumber:isNumber,
isObject:isObject,
isString:isString,
isArray:isArray,
isFunction:isFunction,
isDate: util.isDate,
isRegExp: util.isRegExp,
isError: util.isError,
isIP: net.isIP,
isIP4: net.isIPv4,
isIP6: net.isIPv6,
isFile:isFile,
isFileAsync:isFileAsync,
isDir:isDir,
isDirAsync:isDirAsync,
isNumberString:isNumberString,
isPromise:isPromise,
isWritable:isWritable,
isBuffer:isBuffer,
isTrueEmpty:isTrueEmpty,
isEmpty:isEmpty,
clone:clone,
mkdir:mkdir,
rmdir:rmdir,
md5:md5,
chmod:chmod,
getFiles:getFiles,
escapeHtml:escapeHtml,
datetime:datetime,
getDateTime:getDateTime,
randomString:randomString
}
数据库操作(mysql)
简单的数据库查询,没有封装sql(懒)
var mysql = require('mysql');
var Promise = require('bluebird');
var dbConfig = Config.db;
var pool = mysql.createPool(dbConfig);
//使用连接池
let query = sql => {
return new Promise((resolve,reject) => {
pool.getConnection((err, connection) => {
connection.query(sql, function(err, result) {
return err ? reject(err) : resolve(result);
});
connection.release();
});
});
};
let insert = (table,data) => {
return new Promise((resolve,reject) => {
pool.getConnection((err, connection) => {
connection.query('INSERT INTO {table} SET ?', data, function(err, result) {
return err ? reject(err) : resolve(result.insertId);
});
connection.release();
});
});
};
//普通连接
let queryTest = sql => {
var connection = mysql.createConnection(dbConfig);
return new Promise((resolve,reject) => {
connection.connect();
connection.query(sql, (err, rows, fields) => {
return err ? reject(err) : resolve(rows);
});
connection.end();
});
};
module.exports = {
query:query,
queryTest:queryTest
};
数据库连接测试代码 (使用了上面定义的run方法)
router.get('/', function(req, res, next) {
// 数据库操作测试
F.run(function* (){
var result = yield Db.query('SELECT * FROM fruitscities limit 5');
var result = yield Db.query('SELECT * FROM fruitscities limit 5');
req.session.admin = '111111111';
console.log(req.session.admin);
res.render('index', { title: 'Express```'});
},next)
});
router.get('/test', function(req, res, next) {
console.log(req.baseUrl);
console.log(req.route);
console.log(req.path);
// 数据库操作测试
F.run(function* (){
var result = yield Db.query('SELECT * FROM fruitscities limit 5');
var result = yield Db.query('SELECT * FROM fruitscities limit 5');
console.log(req.session.admin);
},next)
});
使用nunjucks模板引擎
//模板引擎
var nunjucks = require('nunjucks');
// 模板引擎设置
var env = new nunjucks.configure(path.join(__dirname, 'views'), { // 设置模板文件的目录,为views
autoescape: true,
watch: true,
express: app
});
app.set('view engine', 'html');
使用nunjucks模板标签(用于cms,文章,新闻展示等)
//标签测试
var tags = require(path.resolve(Root, './common/tags'));
//绑定标签
env.addExtension("tagtest",new tags.tagtest());
common/tags.js中的代码
var tags;
var nunjucks = require('nunjucks');
tags = {
tagtest:function(){
//tag标签测试
this.tags = ['tagtest'];
this.parse = function(parser, nodes, lexer) {
let tok = parser.nextToken();
var args = parser.parseSignature(null, true);
parser.advanceAfterBlockEnd(tok.value);
let body = parser.parseUntilBlocks('endtagtest');// 结束标签
parser.advanceAfterBlockEnd();
//return new nodes.CallExtension(this, 'run', args);
return new nodes.CallExtensionAsync(this, 'run', args,[body]); //异步调用
};
this.run = function(context,args,body,callback){
console.log(JSON.stringify(args)); //前台返回参数
var data = [{
id: 1,
city: '北京',
parent: 0,
spelling: 'BeiJing',
abbr: 'BJ',
short: 'B' },
{
id: 2,
city: '上海',
parent: 0,
spelling: 'ShangHai',
abbr: 'SH',
short: 'S' },
{
id: 3,
city: '天津',
parent: 0,
spelling: 'TianJin',
abbr: 'TJ',
short: 'T' },
{
id: 4,
city: '重庆',
parent: 0,
spelling: 'ZhongQing',
abbr: 'ZQ',
short: 'Z' },
{
id: 5,
city: '黑龙江',
parent: 0,
spelling: 'HeiLongJiang',
abbr: 'HLJ',
short: 'H' } ];
context.ctx['list'] = data; //返回参数
let result = new nunjucks.runtime.SafeString(body());
return callback(null,result);
}
}
};
module.exports = tags;
页面中使用
{% tagtest list="key1=1,key2=2,key3=3,key4=4" %}
{% for val in list %}
{{ val.id }}:{{ val.city}}
{% endfor %}
{% endtagtest %}
{% tagtest key1=1,key2=2,key3=3,key4=4 %}
{% for val in list %}
{{ val.id }}:{{ val.city}}
{% endfor %}
{% endtagtest %}
使用log4js进行日志记录
记录access日志
app.use(log4js.connectLogger(log4js.getLogger('log_access'), {level:'INFO'}));
配置文件 (配置可以根据需求修改)
module.exports = {
db: {
host : '',
user : '',
password : '',
database : ''
},
cookieSession: {
name: 'session_uuice',
keys: ['key1', 'key2'],
secret: 'ksjf493248kjkj'
},
log4js :{
"appenders":
[
{
"type":"console",
"category":"console"
},
{
"category":"log_file",
"type": "file",
"filename": "./logs/log_file/file.log",
"maxLogSize": 104800,
"backups": 100
},
{
"category":"log_date",
"type": "dateFile",
"filename": "./logs/log_date/date",
"alwaysIncludePattern": true,
"pattern": "-yyyy-MM-dd-hh.log"
},
{
"category":"log_access",
"type": "dateFile",
"filename": "./logs/log_access/date",
"alwaysIncludePattern": true,
"pattern": "-yyyy-MM-dd-hh.log"
}
],
"replaceConsole": true,
"levels":
{
"log_file":"ALL",
"console":"ALL",
"log_date":"ALL"
}
}
};
其他记录日志代码
console.log("log_start start!");
var LogFile = log4js.getLogger('log_file');
LogFile.trace('This is a Log4js-Test');
LogFile.debug('We Write Logs with log4js');
LogFile.info('You can find logs-files in the log-dir');
LogFile.warn('log-dir is a configuration-item in the log4js.json');
LogFile.error('In This Test log-dir is : \'./logs/log_test/\'');
console.log("log_start end!");
var log_date = log4js.getLogger('log_date');
log_date.trace('This is a Log4js-Test');
log_date.debug('We Write Logs with log4js');
log_date.info('You can find logs-files in the log-dir');
log_date.warn('log-dir is a configuration-item in the log4js.json');
log_date.error('In This Test log-dir is : \'./logs/log_test/\'');
console.log("log_date end!");
socket通讯
使用socket.io 在项目bin/www中添加
//添加socket.io支持
var io = require('socket.io')(server);
io.on('connection', function(socket){
Socket(socket,io); //这里的Socket,就是app.js定义的全局变量
});
在app.js中添加事件逻辑
//socket事件方法
global.Socket = require(path.resolve(Root, './socket/socket'));
错误处理 Promise中的报错
let run = (fn,next) =>{
co(fn).catch((err) => {
next(err);
});
};
其他报错
// 将404交给错误处理中间件
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// 错误处理
//开发环境报错,显示错误堆栈
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
if(req.xhr){
res.json({
status: err.status,
message: err.message,
error: err.stack
});
}else{
res.render('error', {
status: err.status,
message: err.message,
error: err
});
}
});
}
//生产环境报错,不展示错误堆栈
app.use(function(err, req, res, next) {
res.status(err.status || 500);
if(req.xhr){
res.json({
status: err.status,
message: err.message,
error: {}
});
}else{
res.render('error', {
status: err.status,
message: err.message,
error: {}
});
}
});
其他
待补充