對於node.js開發指南中部落格案例的修改實現(二)--程式碼
阿新 • • 發佈:2019-02-06
OK,廢話少說,直接上程式碼
首先是app.js,裡面很多與書中介紹的不同,不過看起來都很容易懂。首先是各種模組引用,然後就是使用session儲存狀態。
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); varsession = require('express-session');//需要專案目錄下npm install 安裝模組 var MongoStore = require('connect-mongo')(session);//需要專案目錄下npm install connect-mongo 安裝模組 var settings = require("./settings"); var flash = require('connect-flash');//需要專案目錄下npm install connect-flash 安裝模組 var routes = require('./routes/index'); varusers = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // uncomment after placing your favicon in /public //app.use(favicon(__dirname + '/public/favicon.ico')); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(require('less-middleware')(path.join(__dirname, 'public'))); app.use(express.static(path.join(__dirname, 'public'))); app.use(flash()); app.use(session({ secret:settings.coolieSecret,//express.cookieParser() 是 Cookie 解析的中介軟體 //store引數為MongoStore例項,把會話資訊儲存到資料庫中,以避免丟失。 store:new MongoStore({ db:settings.db }), resave:true, saveUninitialized:true })); //獲取狀態 app.use(function(req,res,next){ console.log("app.user local"); res.locals.user = req.session.user; res.locals.post = req.session.post; var error = req.flash('error'); res.locals.error = error.length?error:null; var success = req.flash('success'); res.locals.success = success.length?success:null; next(); }); app.use('/', routes); app.use('/users', users); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handlers // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } // production error handler // no stacktraces leaked to user app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app;
下面看看路由控制routes/index.js:程式碼中都有註釋。其中需要注意的是中文引數的處理(先base64編碼再解碼)
var express = require('express'); var crypto = require('crypto'); var router = express.Router(); var settings = require("../settings"); var User = require("../models/user.js"); var Post = require("../models/post.js"); var iconv = require('iconv-lite'); /* GET home page. */ /* router.get('/', function(req, res, next) { res.render('index', { title: settings.title }); }); */ router.get('/',function(req,res){ Post.get(null,function(err,posts){ if(err){ posts = []; } res.render('index',{title:"首頁",posts:posts}); }); }); router.get('/reg',checkNotLogin); router.get('/reg',function(req,res){ res.render('reg',{title:"註冊"}); }); //註冊事件處理 router.post('/reg',checkNotLogin); router.post('/reg',function(req,res){ console.log(req.body); //檢測兩次輸入的密碼是否相同 //req.body 就是 POST 請求資訊解析過後的物件,例如我們要訪問使用者傳遞的password 域的值,只需訪問 req.body['password'] 即可。 if(req.body['password-repeat'] != req.body['password']){ //req.flash 是 Express 提供的一個奇妙的工具,通過它儲存的變數只會在使用者當前和下一次的請求中被訪問,之後會被清除, //通過它我們可以很方便地實現頁面的通知和錯誤資訊顯示功能 req.flash('error','兩次輸入的口令不一致'); return res.redirect('/reg'); } //生成口令的雜湊值 //crypto 是 Node.js 的一個核心模組,功能是加密並生成各種雜湊, //使用它之前首先要宣告 var crypto = require('crypto')。我們程式碼中使用它計算了密碼的雜湊值。 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 is already exists. "; } if(err){ req.flash('error',err); console.log(err); return res.redirect('/reg'); } console.log("save"); //不存在則儲存新使用者 newUser.save(function(err){ if(err){ req.flash('error',err); console.log(err); console.log("save err"); return res.redirect('/reg'); } req.session.user = newUser; req.flash('success','註冊成功'); return res.redirect('/'); }); }); }); //登入 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','登入成功'); return res.redirect('/'); }) }); //登出 router.get('/logout',checkLogin); router.get('/logout', function (req,res) { req.session.user = null; req.flash('success','登出成功'); res.redirect('/'); }); //發表處理 router.post('/post',checkLogin); router.post('/post',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','發表成功'); console.log('/u/'+currentUser.name); var pramsUserNnametemp = new Buffer(currentUser.name); var pramsUserNname = pramsUserNnametemp.toString('base64');//為了解決中文引數問題將引數base64編碼,然後解碼 // res.redirect('/u/'+currentUser.name); res.redirect('/u/'+pramsUserNname); }); }); router.get("/u/:user",function(req,res){ var uNametemp = new Buffer(req.params.user,'base64');//base64解碼 var uName = uNametemp.toString(); //User.get(req.params.user, function(err,user){ User.get(uName, function(err,user){ if(!user){ req.flash('error','使用者不存在'); res.redirect('/'); } Post.get(user.name,function(err,posts){ if(err){ req.flash('error',err); res.redirect('/'); } res.render('user',{title:user.name,posts:posts}); }); }); }); 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;
在看一下models目錄下的user.js,就是對mongodb的操作,儲存查詢
var mongodb = require('./db'); function User(user){ this.name = user.name; this.password = user.password; }; module.exports = User; User.prototype.save = function save(callback){ //存入mongodb的文件 var user = { name:this.name, password:this.password }; mongodb.open(function(err,db){ if(err){ return callback(err); } //讀取users集合 db.collection('users',function(err,collection){ if(err){ mongodb.close(); return callback(err); } //為name屬性新增索引,新版本的ensureIndex方法需要一個回撥函式 collection.ensureIndex('name',{unique:true},function(err){ //寫入user文件 collection.insert(user,{safe:true},function(err,user){ mongodb.close(); callback(err,user); }); }); }); }); }; User.get = function get(username,callback){ mongodb.open(function(err,db){ if(err){ return callback(err); } //讀取users集合 db.collection('users',function(err,collection){ if(err){ mongodb.close(); return callback(err); } //查詢name屬性為username的文件 collection.findOne({name:username},function(err,doc){ mongodb.close(); if(doc){ //封裝文件為User物件 var user = new User(doc); callback(err,user); } else{ callback(err,null); } }); }); }); };post.js:
var mongodb = require("./db"); function Post(username,post,time){ this.user = username; this.post = post; if(time){ this.time = time; } else{ this.time = new Date(); } }; module.exports = Post; Post.prototype.save = function save(callback){ //存入Mongodb的文件 var post = { username:this.user, post:this.post, time:this.time }; mongodb.open(function(err,db){ if(err){ return callback(err); } //讀取posts集合 db.collection('posts',function(err,collection){ if(err){ mongodb.close(); return callback(err); } //為user屬性新增索引 collection.ensureIndex('user',function(err){ //寫入post文件 collection.insert(post,{safe:true},function(err,post){ mongodb.close(); callback(err,post); }); }); }); }); }; Post.get = function get(username,callback){ mongodb.open(function(err,db){ if(err){ return callback(err); } //讀取posts集合 db.collection('posts',function(err,collection){ if(err){ mongodb.close(); return callback(err); } //查詢user屬性為username的文件,如果sername是null則全部匹配 var query = {}; if(username){ query.username = username; } collection.find(query).sort({time:-1}).toArray(function(err,docs){ mongodb.close(); if(err){ callback(err,null); } //封裝posts為Post物件 var posts = []; docs.forEach(function(doc,index){ var post = new Post(doc.username,doc.post,doc.time); posts.push(post); }); callback(null,posts); }); }); }); };
主要的程式碼就這些了,跟書中的差別還是很大的,主要模組更新太快,書更新的速度跟不上技術的更新。