使用express4.x版、Jade模板以及mysql重写《nodejs开发指南》微博实例
最近阅读《nodejs开发指南》一书,书是不错的,然而其微博代码示例用的是express3.x,用些过时了,运行代码出现不少bug(我电脑安的是express4.x),于是用express4.x+jade模板重写一遍(原代码使用的是ejs模板)。因为想体验一下node结合MySQL开发,于是将mongodb改为mysql。下面进入正文
1、安装express框架与生成器:


2、进入网站目录,创建项目:

3、安装中间件与依赖项:

package.json如下

单独安装时记得加上--save,便于项目迁移重新安装中间件。
4、启动项目:
先安装supervisor,启动实时监控文件修改并重新启动服务器,这样就不用每次修改文件都重新启动服务器。

启动项目

5、看看我的项目目录

configs放配置文件,写法遵循commonjs规范。
install放安装所需文件,安装时读取sql代码连接数据库创建数据表并插入数据,有后台管理时创建保存管理员账号,完成安装时声称lock.txt文件。方便项目迁移。
log放日志文件,access是访问日志,error是错误日志
public放静态资源文件。
models为模型操作文件,相当于为MVC中的M;routes为路由文件,相当于为MVC中的C以及路由解析分发;view为V,视图层。
utils防止工具类文件以及第三方工具类文件
cluster.js为充分调用电脑多核资源所写,根据核数量创建相应数量进程运行app.js。运行 supervisor cluster.js
6、下面看源代码:
cluster.js
var cluster = require('cluster');
var os = require('os');
var cpuNum = os.cpus().length;
var workers = {};
if(cluster.isMaster){ //主进程
//当一个进程结束,重启工作进程
cluster.on('death',function(worker){
delete workers[worker.pid];
worker = cluster.fork();
workers[worker.pid] = worker;
})
//根据CPU数量创建相应数量的进程
for(var i=0; i<cpuNum;i++){
var worker = cluster.fork();
workers[worker.pid] = worker;
}
}else{//工作进程
var app = require('./app');
app.listen(3000);
}
//当主进程终止,关闭所有主进程
process.on('SIGTERM',function(){
for(var pid in workers){
precess.kill(pid);
}
process.exit(0);
})
app.js
var express = require('express');
var logger = require('morgan');
var fs = require('fs');
var fileStreamRotator = require('file-stream-rotator')
var cookieParser = require('cookie-parser');
var session = require('express-session');
var bodyParser = require('body-parser');
var path = require('path');
var favicon = require('serve-favicon');
var flash = require('connect-flash');
var index = require('./routes/index');
var user = require('./routes/user');
var app = express();
// 设置模板引擎与模板目录
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// 日志输出到文件系统,每日一个日志文件
var accessLogDirectory = __dirname + '/logs/access';
fs.existsSync(accessLogDirectory) || fs.mkdirSync(accessLogDirectory);
var errorLogDirectory = __dirname + '/logs/error';
fs.existsSync(errorLogDirectory) || fs.mkdirSync(errorLogDirectory);
var accessLogStream = fileStreamRotator.getStream({
filename:accessLogDirectory+'/access-%DATE%.log',
frequency:'daily',
verbose:false
})
app.use(logger('combined',{stream:accessLogStream}));
// 设置错误日志文件地址
var errorLogStream = fs.createWriteStream(errorLogDirectory+'/error.log',{'flags':'a'});
//将请求体放入request.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
//处理cookie
app.use(cookieParser());
//处理session
app.use(session({
secret:'testexpress',
cookie: { maxAge: 60000 },
resave: true,
saveUninitialized: true
}))
// 设置icon图标
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
//flash支持
app.use(flash());
//静态文件借口
app.use(express.static(path.join(__dirname, 'public')));
// 挂靠路由中间件
app.use('/', index);
app.use('/index', index);
app.use('/user', user);
//404错误处理句柄
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
//错误处理
app.use(function(err, req, res, next) {
var error = (req.app.get('env') === 'development' )? err : {};
//写错误日志
var errorMes = '['+Date()+']'+req.url+'\n'+'['+error.stack+']'+'\n';
errorLogStream.write(errorMes);
// 写回错误处理代码
res.status(err.status || 500);
res.render('error',{'message':err.message,'error':error});
});
//防止服务器自启动。只许在外部模块调用
if(!module.parent){
app.listen(3000,function(){
console.log("Server listening on port %d in %s",3000,app.settings.env);
});
}
module.exports = app;
routes/index.js
var express = require('express');
var router = express.Router();
var News = require('../models/news');
/* GET home page. */
router.get('/', function(req, res, next) {
News.get(null,function(err,news){
var user = null;
if(err){
news = [];
}
if(req.session.user){
user = req.session.user;
}
res.render('index/index', {
title: '微博首页',
news:news,
user:user
});
})
});
module.exports = router;
routes/user.js
var express = require('express');
var router = express.Router();
var User = require('../models/user');
var News = require('../models/news');
var crypto = require('crypto');
//访问用户页面
router.get('/:user', function (req, res) {
User.get(req.params.user, function (err, user) {
if (!user) {
console.log(req.session);
req.flash('error', ' 用户不存在');
return res.redirect('/');
}
console.log(user);
News.get(user.username, function (err, news) {
if (err) {
req.flash('error', err);
return res.redirect('/');
}
res.render('user/index', {
username: user.username,
news: news
});
});
});
});
//访问注册页
router.get("/reg",checkNotLogin);
router.get("/reg",function(req,res){
res.render('reg',{
'title':'用户注册'
})
})
//提交注册信息
router.post('/reg',checkNotLogin);
router.post('/reg',function(){
if(req.body['password-repeat']!=req.body['password']){
req.flash('error','两次输入的口令不一致');
return res.redirect('/reg');
}
var md5 = crypto.createHash("md5");
var password = md5.update(req.body.password).digest('base64');
var newUser = new User({
name: req.body.username,
password: password
})
//检查用户名是否已经存在
User.get(newUser.name, function (err, user) {
if (user)
err = 'Username already exists.';
if (err) {
req.flash('error', err);
return res.redirect('/reg');
}
// 如果不存在则新增用户
newUser.save(function (err) {
if (err) {
req.flash('error', err);
return res.redirect('/reg');
}
req.flash('success', ' 注册成功');
res.redirect('/login');
});
});
})
//用户访问登录页
router.get('/login', checkNotLogin);
router.get('/login', function (req, res) {
res.render('login', {
title: '用户登入'
});
});
//用户提交账号信息
router.post('/login',checkNotLogin);
router.post('/login', function (req, res) {
//生成口令的散列值
var md5 = crypto.createHash('md5');
var password = md5.update(req.body.password).digest('base64');
User.get(req.body.username, function (err, user) {
if (!user) {
req.flash('error', ' 用户不存在');
return res.redirect('/login');
}
if (user.password != password) {
req.flash('error', ' 用户密码错误');
return res.redirect('/login');
}
req.session.user = user;
req.flash('success', ' 登入成功');
res.redirect('/');
});
})
//用户退出
router.get('/logout',checkLogin);
router.get('/logout', function (req, res) {
req.session.user = null;
req.flash('success', '登出成功');
res.redirect('/');
});
//找回密码
router.get('/getPwd',checkNotLogin);
router.get('/getPwd',function(req,res){
res.render('getpwd', {
title: '密码找回',
});
})
router.post('/getPwd',checkNotLogin);
router.post('/getPwd',function(req,res){
User.get(req.body.username, function (err, user) {
if (!user) {
req.flash('error', ' 用户不存在');
return res.redirect('/getPwd');
}
req.flash('success', '成功找回密码:'+user.password);
res.redirect('/login');
});
})
//发表微博
router.post('/news', checkLogin);
router.post('/news', function (req, res) {
var currentUser = req.session.user;
var post = new Post(currentUser.name, req.body.post);
post.save(function (err) {
if (err) {
req.flash('error', err);
return res.redirect('/');
}
req.flash('success', ' 发表成功');
res.redirect('/u/' + currentUser.name);
});
});
function checkLogin(req, res, next) {
if (!req.session.user) {
req.flash('error', '未登入');
return res.redirect('/login');
}
next();
}
function checkNotLogin(req, res, next) {
if (req.session.user) {
req.flash('error', '已登入');
return res.redirect('/');
}
next();
}
module.exports = router;
configs/settings.js
(function(){
var settings;
settings = {
mysql:{
host:'localhost',
prot:'3306',
user:'root',
password:'',
database:'node_microblog'
},
mongodb:{
host:'localhost',
prot:'27017',
user:'root',
password:'',
database:'node_microblog'
}
}
module.exports = settings;
})()
utils/database.js
(function(){
var settings = require('../configs/settings');
var mysql = require('mysql');
var client = null;
var default_sql = require
exports.getDbCon = function(){
try{
if(client){
client = mysql.createConnection(settings.mysql);
client.connect();
}else{
client = new mysql.createConnection(settings.mysql);
client.connect();
}
}catch(_error){
throw _error;
}
return client;
}
exports.install = function(){
}
})()
models/news.js
var database = require('../utils/database');
mysql = database.getDbCon();
function News(username,content,time){
this.username = username;
this.content = content;
if (time) {
this.time = time;
} else {
this.time = new Date ();
console.log(this.time);
}
}
//保存消息
News.prototype.save = function(callback){
var sql = "select id from user where username = '"+this.username+"'";
mysql.query(sql,function(err,results,fields){
if(err){
throw err;
}
if(results){
this.uid = results[0].id;
}
var news = {
username: this.uid,
content: this.conetnt,
time: this.time
};
sql = "insert into user(uid,content,time) values(?,?,?)";
mysql.query(sql,[news.uid,news.content,news.time],function(err,results,fields){
if (err) {
throw err;
} else {
//返回用户id
return callback(err,fields);
}
})
})
};
//获取消息
News.get = function(username,callback){
var sql ="select * from news";
if( username){
sql +=" join user on user.id=news.uid where username='"+username+"'";
}
mysql.query(sql,function(err,results,fields){
if(err){
throw err;
}else{
callback(err,results,fields);
}
})
}
module.exports = News;
models/user.js
var database = require('../utils/database');
mysql = database.getDbCon();
function User(user){
this.username = user.username;
this.password = user.password;
}
//保存用户
User.prototype.save = function(callback){
var user = {
username: this.username,
password: this.password
};
var sql ="insert into user (username,password) values(?,?)";
mysql.query(sql,[user.username,user.password],function(err,results,fields){
if (err) {
throw err;
} else {
//返回用户id
return callback(err,fields);
}
});
};
//获取用户
User.get = function(id,callback){
var sql = "select * from user where id='"+id+"'";
mysql.query(sql,function(err,results,fields){
if(err){
throw err;
}else{
callback(err,results[0],fields);
}
})
}
module.exports = User;
源代码下载:https://github.com/yujon/node_microblog
使用express4.x版、Jade模板以及mysql重写《nodejs开发指南》微博实例的更多相关文章
- 《nodejs开发指南》微博实例express4.x版
之前一直执着于前端开发,最近几天,开始学起了nodejs.作为一名前端开发者,见到这样一门用javascript写的后台自然是很激动的.但是,后台毕竟不同于前端,在学习的过程中,还是会遇到不少问题. ...
- 75.《nodejs开发指南》express4.x版-微博案例完整实现
转自:https://blog.csdn.net/cgwcgw_/article/details/39317587 完整代码下载 https://github.com/haishangfeie/wei ...
- 学习Nodejs:《Node.js开发指南》微博项目express2迁移至express4过程中填的坑
<Node.js开发指南>项目地址https://github.com/BYVoid/microblog好不容易找到的基础版教程,但书中是基于express2的,而现在用的是express ...
- Node.js开发指南中的例子(mysql版)
工作原因需要用到nodejs,于是找到了<node.js开发指南>这本书来看看,作者BYVoid 为清华大学计算机系的高材生,年纪竟比我还小一两岁,中华地广物博真是人才辈出,佩服. 言归正 ...
- Jade 模板引擎使用
在 Express 中调用 jade 模板引擎 jade 变量调用 if 判断 循环 Case 选择 在模板中调用其他语言 可重用的 jade 块 (Mixins) 模板包含 (Includes) 模 ...
- zabbix利用自带的模板监控mysql数据库
zabbix利用自带的模板监控mysql数据库 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 有些东西你不会的时候觉得它特别难,但是当你去做的时候就发现如此的简单~zabbix功能 ...
- jade模板
jade 模板使用 npm install jade -g 安装到全局 jade index.jade 导出一个 index.html 压缩后的 jade -P index. ...
- 写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)
前些时间在看创智博客韩顺平的Smarty模板引擎教程,再结合自己跟李炎恢第二季开发中CMS系统写的tpl模板引擎.今天就写一个迷你版的Smarty引擎,虽然说我并没有深入分析过Smarty的源码,但是 ...
- jade模板引擎学习笔记(WebsStorm9.0.3+ nodejs+express+jade)
jade环境搭建 jade标签写法 jade注释 jade添加类名.id.属性 jade添加脚本,css jade变量 jade多行文本显示 jade流程代码:for,each,while jade流 ...
随机推荐
- 使用PowerDesigner设计数据库
1.快捷键CTRL+N 创建 New Model 选择如下图,并设置 Model name 单击OK 2.使用工具添加实体 双击Entity_1,填上如下图信息 切换选项卡,添加属性信息 其中 M ...
- MakeFile 文件的使用
什么是Makefile? 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译, ...
- selenium_page_object
最简单的pageobject github地址:https://github.com/defnngj/selenium_page_objects
- vs未能正确加载XX包的解决方法
管理员 -- cmd ---(进入到vs的安装目录下.如我的是:C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE)---d ...
- JVM 内存区域
JVM 将内存区域划分为: Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟机栈, ...
- Game of Peace
Time Limit: 4000ms, Special Time Limit:10000ms, Memory Limit:65536KB Total submit users: 20, Accepte ...
- apk重签名的两种方法
因为robotium要求被测应用和测试代码要有一致的签名, 所以需要将apk包重签名. 方法一:通过re-sign.jar来产生debug key的apk(不适用于jdk 7以上) re-sign.j ...
- 洛谷1601 A+B Problem(高精) 解题报告
洛谷1601 A+B Problem(高精) 本题地址:http://www.luogu.org/problem/show?pid=1601 题目背景 无 题目描述 高精度加法,x相当于a+b pro ...
- jQuery获取table当前所在行
$("div tbody tr").click(function() { var rows = $(this).prevAll().length + 1;//行号 ...
- C#项目中一些文件类型说明
designer.cs 是窗体设计器生成的代码文件,作用是对窗体上的控件做初始化工作 (在函数InitializeComponent()中)VS2003以前都把这部分代码放到窗体的cs文件中,由于这 ...