nodejs是目前前端开发中会使用的服务端语言,Express是基于nodejs产生的Web开发框架,MongoDB是一个使用较广泛的非关系型数据库,以键值对的形式存储内容。因为对express和MongoDB都不算熟悉,所以为练习和基础入门,参考网上点击打开链接及自己摸索,实现个人博客搭建,分享如下。
整个过程主要分为以下几步:
$ express -e test
在创建的过程中,可能会有没有安装的模块,可以根据提示使用npm进行安装。
创建成功之后,进入项目根目录,命令:
node ./bin/www
默认端口为3000,打开浏览器访问localhost:3000就可以访问Express的index页面。
下面看一下test项目下的文件目录:
app.js是整个项目的引导文件,里面主要加载该项目用到的所有模块,同时持久化session,设置路由文件和基本的出错处理,最后将整个文件export出来。
package.json是项目的配置信息和依赖模块的配置信息,所有信息以键值对的形式定义。当需要新的模块的时候,都需要修改依赖包文件。
routes为项目的路由文件,主要存放请求的处理。public为公共文件夹,存放前台相关的JS,CSS和图片等一系列资源。node_modules为项目的依赖模块,包含所有在package.json里声明过的模块。models为操作数据库的文件,在后面会进行详细说明。
mongod --dbpath=D:\mongodb\test
Nodejs里的mongodb主要是提供操作mongodb的方法的模块有两个
使用npm安装之后,在安装依赖模块的时候,建议先使用npm安装,安装完成后查看安装模块的版本,再把版本号写入package.json里,这样避免npm找不到你想要的版本的模块。
可以在项目的根目录下创建setting.js写入数据库的配置信息,也是以键值对的形式:
module.exports = {
db: 'test',
host: 'localhost',
port: 27017
};
提醒一下,mongodb是默认可以进行CURD操作的,不需要用户名和密码,如果你自己需要就创建用户,具体操作不多说。
为了保证用户登录等的会话保持和写入持久层方便操作,引入express-session 和 connect-mongo 这两个第三方中间件,方便序列化操作session等会话信息,并保存在数据库中。
创建配置信息文件之后,在app.js里写入保存会话的代码,如下:
// session的持久化防止丢失
app.use(session({
secret: settings.cookieSecret,
key: settings.db,//cookie name
cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},//30 days
resave: false,
saveUninitialized: true,
store: new MongoStore({
url:('mongodb://localhost:27017/test'),
})
}));
注意,这里的存储路径写法如下,写入的是可以直接访问的路径。
根据页面的布局,我们采用ejs作为模板文件,主要规划有header,footer,index,login,logout,reg和post这些页面,以index页面为例,文件如下:
<%- include header %>
<% posts.forEach(function (post, index) { %>
<%= post.title %>
作者:<%= post.name %> |
日期:<%= post.time.minute %>
<%- post.post %>
<% }) %>
<%- include footer %>
所有对请求的操作及路由,都需要放在路由文件夹下的index文件里,因为此处方法不多,可以直接写到一个js里。在app.js里,只需要引入router下的文件保证路由可用。
var routes = require('./routes/index');
app.use('/', routes);
在routes下的index.js里,需要写入所有的路由方法,具体如下:
var express = require('express');
var router = express.Router();
var crypto = require('crypto');
var User = require('../models/user.js');
var Post = require('../models/post.js')
/* GET home page. */
router.get('/', function(req, res, next) {
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()
});
});
});
router.get('/login',checkNotLogin);
router.get('/login',function(req,res){
res.render('login', {
title: '登录',
user: req.session.user,
success: req.flash('success').toString(),
error: req.flash('error').toString()});
});
router.post('/login',checkNotLogin);
router.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('/');//登陆成功后跳转到主页
});
});
router.post('/reg',checkNotLogin);
router.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 (err) {
req.flash('error', err);
return res.redirect('/');
}
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 = newUser;//用户信息存入 session
req.flash('success', '注册成功!');
res.redirect('/');//注册成功后返回主页
});
});
});
router.get('/reg',checkNotLogin);
router.get('/reg', function (req, res) {
res.render('reg', {
title: '注册',
user: req.session.user,
success: req.flash('success').toString(),
error: req.flash('error').toString()
});
});
router.get('/post',checkLogin);
router.get('/post',function(req,res){
res.render('post',{
title:'发表',
user: req.session.user,
success: req.flash('success').toString(),
error: req.flash('error').toString()
});
});
router.post('/post',checkLogin);
router.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('/');//发表成功跳转到主页
});
});
router.get('/logout',checkLogin);
router.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();
}
module.exports = router;
在所有的方法中,都将session中的user输出至页面上,同时,在查询时将查询出的数据输出出去,在view文件夹下的对应模板文件里,可以直接使用
<%= name %>
的方法显示数据。同时,针对所有页面的权限,进行了权限检查,针对注册页面和登录界面,已经登录的用户不能查看,直接使用redirect重定向至首页,对于发布博客页面,未登录用户不能查看。
var settings = require('../setting.js'),
Db = require('mongodb').Db,
Connection = require('mongodb').Connection,
Server = require('mongodb').Server;
module.exports = new Db(settings.db, new Server(settings.host, settings.port),
{safe: true});
这里以用户为例子,主要有创建用户和用户登录两个方法,具体代码如下:
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);//成功!返回查询的用户信息
});
});
});
};