1. 程式人生 > >對於node.js開發指南中部落格案例的修改實現(二)--程式碼

對於node.js開發指南中部落格案例的修改實現(二)--程式碼

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');

var 
session = 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'); var
users = 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);
         });
      });
   });
};


主要的程式碼就這些了,跟書中的差別還是很大的,主要模組更新太快,書更新的速度跟不上技術的更新。