Node.js 一个简单的博客实例

原教程 https://github.com/nswbmw/N-blog/wiki/_pages的第一章,由于版本等的原因,在原教程基础上稍加改动即可实现。

环境:

win7旗舰版64位

Node.js:0.10.31

mongodb:2.6.4

express:3.×

效果:

注册界面:

登录界面:

登录成功:

发表博客:

发表成功:

源代码:

blog/

blog/package.json

{
  "name": "blog",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.16.7",
    "ejs": "*",
	"mongodb":"*",
	"connect-mongo":"*",
	"connect-flash":"*"
  }
}

blog/app.js

/**
 * Module dependencies.
 */

var express = require('express');
var routes = require('./routes');
var http = require('http');
var path = require('path');
var MongoStore=require('connect-mongo')(express);
var settings=require('./settings');
var flash=require('connect-flash');
var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(flash());
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());

app.use(express.static(path.join(__dirname, 'public')));
app.use(express.cookieParser());
app.use(express.session({
  secret: settings.cookieSecret,
  key: settings.db,//cookie name
  cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},//30 days
  store: new MongoStore({
    db: settings.db
  })
}));
//此句写在session前面就会出错 为啥捏
app.use(app.router);

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

routes(app);

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

blog/settings.js

module.exports={
	cookieSecret:'myblog',
	db:'blog',
	host:'localhost'
};

blog/models/

blog/models/db.js

var settings=require('../settings'),
	Db=require('mongodb').Db,
	Connection=require('mongodb').Connection,
	Server=require('mongodb').Server;
module.exports=new Db(settings.db,new Server(settings.host,Connection.DEFAULT_PORT), {safe: true});

blog/models/post.js

var mongodb = require('./db');

function Post(name, title, post) {
  this.name = name;
  this.title = title;
  this.post = post;
}

module.exports = Post;

//存储一篇文章及其相关信息
Post.prototype.save = function(callback) {
  var date = new Date();
  //存储各种时间格式,方便以后扩展
  var time = {
      date: date,
      year : date.getFullYear(),
      month : date.getFullYear() + "-" + (date.getMonth() + 1),
      day : date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(),
      minute : date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + 
      date.getHours() + ":" + (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) 
  }
  //要存入数据库的文档
  var post = {
      name: this.name,
      time: time,
      title: this.title,
      post: this.post
  };
  //打开数据库
  mongodb.open(function (err, db) {
    if (err) {
      return callback(err);
    }
    //读取 posts 集合
    db.collection('posts', function (err, collection) {
      if (err) {
        mongodb.close();
        return callback(err);
      }
      //将文档插入 posts 集合
      collection.insert(post, {
        safe: true
      }, function (err) {
        mongodb.close();
        if (err) {
          return callback(err);//失败!返回 err
        }
        callback(null);//返回 err 为 null
      });
    });
  });
};

//读取文章及其相关信息
Post.get = function(name, 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);
      }
      var query = {};
      if (name) {
        query.name = name;
      }
      //根据 query 对象查询文章
      collection.find(query).sort({
        time: -1
      }).toArray(function (err, docs) {
        mongodb.close();
        if (err) {
          return callback(err);//失败!返回 err
        }
        callback(null, docs);//成功!以数组形式返回查询的结果
      });
    });
  });
};

blog/models/user.js


var mongodb = require('./db');

function User(user) {
  this.name = user.name;
  this.password = user.password;
  this.email = user.email;
};

module.exports = User;

//存储用户信息
User.prototype.save = function(callback) {
    //要存入数据库的用户文档
    var user = {
		name: this.name,
		password: this.password,
		email: this.email
	};
  //打开数据库
    mongodb.open(function (err, db) {
    if (err) {
        return callback(err);//错误,返回 err 信息
    }
    //读取 users 集合
    db.collection('users', function (err, collection) {
        if (err) {
			mongodb.close();
			return callback(err);//错误,返回 err 信息
        }
      //将用户数据插入 users 集合
        collection.insert(user, {
			safe: true
        }, 
		function (err, user) {
			mongodb.close();
			if (err) {
				return callback(err);//错误,返回 err 信息
			}
			callback(null, user[0]);//成功!err 为 null,并返回存储后的用户文档
        });
    });
  });
};

//读取用户信息
User.get = function(name, callback) {
  //打开数据库
    mongodb.open(function (err, db) {
    if (err) {
		return callback(err);//错误,返回 err 信息
    }
    //读取 users 集合
    db.collection('users', function (err, collection) {
        if (err) {
			mongodb.close();
			return callback(err);//错误,返回 err 信息
		}
      //查找用户名(name键)值为 name 一个文档
        collection.findOne({
			name: name
        }, 
		function (err, user) {
			mongodb.close();
			if (err) {
				return callback(err);//失败!返回 err 信息
			}
			callback(null, user);//成功!返回查询的用户信息
        });
    });
  });
};

blog/public/

blog/public/stylesheets/style.css

/* inspired by http://yihui.name/cn/ */
*{padding:0;margin:0;}
body{width:600px;margin:2em auto;padding:0 2em;font-size:14px;font-family:"Microsoft YaHei";}
p{line-height:24px;margin:1em 0;}
header{padding:.5em 0;border-bottom:1px solid #cccccc;}
nav{position:fixed;left:12em;font-family:"Microsoft YaHei";font-size:1.1em;text-transform:uppercase;width:9em;text-align:right;}
nav a{display:block;text-decoration:none;padding:.7em 1em;color:#000000;}
nav a:hover{background-color:#ff0000;color:#f9f9f9;-webkit-transition:color .2s linear;}
article{font-size:16px;padding-top:.5em;}
article a{color:#dd0000;text-decoration:none;}
article a:hover{color:#333333;text-decoration:underline;}
.info{font-size:14px;}

blog/routes/

blog/routes/index.js

/*
 * GET home page.
 */
var crypto = require('crypto'),
    User = require('../models/user.js'),
    Post=require('../models/post.js');

	
module.exports = function(app) {
    app.get('/', function (req, res) {
			Post.get(null, function (err, posts) {
    		if (err) {
     		 posts = [];
   			} 
    		res.render('index', {
     	 		title: '主页',
      		user: req.session.user,
      		posts: posts,
      		success: req.flash('success').toString(),
      		error: req.flash('error').toString()
    		});
  		});
    });
	
	app.get('/reg', checkNotLogin);
    app.get('/reg', function (req, res) {
		res.render('reg', {
			title: '注册',
			user: req.session.user,
			success: req.flash('success').toString(),
			error: req.flash('error').toString()
		});
    });
	
	app.post('/reg', checkNotLogin);
    app.post('/reg', function (req, res) {
		var name = req.body.name,
        password = req.body.password,
        password_re = req.body['password-repeat'];
		//检验用户两次输入的密码是否一致
		if (password_re != password) {
			req.flash('error', '两次输入的密码不一致!'); 
			return res.redirect('/reg');//返回注册页
		}
		//生成密码的 md5 值
		var md5 = crypto.createHash('md5'),
		password = md5.update(req.body.password).digest('hex');
		var newUser = new User({
			name: name,
			password: password,
			email: req.body.email
		});
		//检查用户名是否已经存在 
		User.get(newUser.name, function (err, user) {
			if (user) {
				req.flash('error', '用户已存在!');
				return res.redirect('/reg');//返回注册页
			}
			//如果不存在则新增用户
			newUser.save(function (err, user) {
				if (err) {
					req.flash('error', err);
					return res.redirect('/reg');//注册失败返回主册页
				}
				req.session.user = user;//用户信息存入 session
				req.flash('success', '注册成功!');
				res.redirect('/');//注册成功后返回主页
			});
		});
    });
	
    app.get('/login', checkNotLogin);
    app.get('/login', function (req, res) {
		res.render('login', {
        title: '登录',
        user: req.session.user,
        success: req.flash('success').toString(),
        error: req.flash('error').toString()});
	});
	
	app.post('/login', checkNotLogin);
	app.post('/login', function (req, res) {
		//生成密码的 md5 值
		var md5 = crypto.createHash('md5'),
		password = md5.update(req.body.password).digest('hex');
		//检查用户是否存在
		User.get(req.body.name, function (err, user) {
			if (!user) {
				req.flash('error', '用户不存在!'); 
				return res.redirect('/login');//用户不存在则跳转到登录页
			}
			//检查密码是否一致
			if (user.password != password) {
				req.flash('error', '密码错误!'); 
				return res.redirect('/login');//密码错误则跳转到登录页
			}
			//用户名密码都匹配后,将用户信息存入 session
			req.session.user = user;
			req.flash('success', '登陆成功!');
			res.redirect('/');//登陆成功后跳转到主页
		});
	});
	
	app.get('/post', checkLogin);
	app.get('/post', function (req, res) {
		res.render('post', { 
			title: '发表' ,
			user: req.session.user,
			success: req.flash('success').toString(),
			error: req.flash('error').toString()});
		
		console.log("222");
	});
	
	app.post('/post', checkLogin);
	app.post('/post', function (req, res) {
		
		var currentUser = req.session.user,		
		post = new Post(currentUser.name, req.body.title, req.body.post);
		post.save(function (err) {
			if (err) {
				req.flash('error', err); 
				return res.redirect('/');
			}
			req.flash('success', '发布成功!');
			res.redirect('/');//发表成功跳转到主页
		});
	});
	
	app.get('/logout', checkLogin);
	app.get('/logout', function (req, res) {
		req.session.user = null;
		req.flash('success', '登出成功!');
		res.redirect('/');//登出成功后跳转到主页
	});
	
	function checkLogin(req, res, next) {
		if (!req.session.user) {
			req.flash('error', '未登录!'); 
			res.redirect('/login');
		}
		next();
	}

	function checkNotLogin(req, res, next) {
		if (req.session.user) {
			req.flash('error', '已登录!'); 
			res.redirect('back');
		}
		next();
	}
};

blog/views/

blog/views/header.ejs

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Blog</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>

<header>
<h1><%= title %></h1>
</header>

<nav>
<span><a title="主页" href="/">home</a></span>
<% if (user) { %>
  <span><a title="发表" href="/post">post</a></span>
  <span><a title="登出" href="/logout">logout</a></span>
<% } else { %>
  <span><a title="登录" href="/login">login</a></span>
  <span><a title="注册" href="/reg">register</a></span>
<% } %>
</nav>

<article>

<% if (success) { %>
  <div><%= success %></div>
<% } %>
<% if (error) { %>
  <div><%= error %> </div>
<% } %>

blog/views/footer.ejs

</article>
</body>
</html>

blog/views/index.ejs

<%- include header %>
<% posts.forEach(function (post, index) { %>
  <p><h2><a href="#"><%= post.title %></a></h2></p>
  <p class="info">
    作者:<a href="#"><%= post.name %></a> | 
    日期:<%= post.time.minute %>
  </p>
  <p><%- post.post %></p>
<% }) %>
<%- include footer %>

blog/views/reg.ejs

<%- include header %>
<form method="post" url='/reg'>
  用户名:  <input type="text" name="name"/><br />
  密码:    <input type="password" name="password"/><br />
  确认密码:<input type="password" name="password-repeat"/><br />
  邮箱:    <input type="email" name="email"/><br />
           <input type="submit" value="注册"/>
</form>
<%- include footer %>

blog/views/login.ejs

<%- include header %>
<form method="post">
  用户名:<input type="text" name="name"/><br />
  密码:  <input type="password" name="password"/><br />
         <input type="submit" value="登录"/>
</form>
<%- include footer %>

blog/views/post.ejs

<%- include header %>
<form method="post" url='/post'>
  TITLE:<br />
  <input type="text" name="title" /><br />
  DETAIL:<br />
  <textarea name="post" rows="20" cols="100"></textarea><br />
  <input type="submit" value="POST" />
</form>
<%- include footer %>

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。