使用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