开始这个个人小项目已经有一段时间了,一直断断续续的,直到今天总算是初见雏形,所以就很想和大家分享一下实现的过程。首先这个的初衷就是学习nodejs,看了几天的书,自己就照着书上的代码来敲,可是由于自己安装的node是最新版,然而书比较旧,好多都不能正确运行,我想了解node的都知道它几乎每天都在更新,出现这样的情况也是必然的。所以想了下,还是在github上找个别人的项目拿来练练手,看一下项目是如何搭建的,经过仔细的琢磨总算是慢慢搭起来了。下来讲一下自己是如何实现的。
一. 项目所用到的技术
express框架:
(1)可以设置中间件来响应 HTTP 请求;
(2)定义路由表用于执行不同的 HTTP 请求动作;
ejs模板
用过Java的jsp的就知道,这和jsp的作用完全相同,动态生成html元素。
mongodb数据库
这和熟悉的mysql数据库不同,mysql是关系型数据库,没一个表的每一项时一条记录,而mongodb是集合类型的,每个集合里存储的是对象,想象一下json,就明白mongodb里存储的数据类型。
mongoose数据库操作
这个是针对mongodb的数据库驱动,里面封装了对数据库的各种基本操作。
二. 项目目录
下面介绍下,每个目录都是干什么的:
(1)node_modules:存放各种node插件和express框架;
(2)schemas:在这个文件里用mongoose封装的对象来指定,数据库里要存储的数据结构。
如下,这是一个user的数据集合里面存储的数据项的结构:
> schemas/user.js
var Schema = require('mongoose').Schema;
var userSchema = new Schema({
name: String,
password: String,
icon: String,
sex: String,
tel: String,
qq: String,
weixin: String,
weibo: String,
email: String
});
module.exports = userSchema;
(3)models:此文件夹下的每一个js文件都映射一个对应的schemas里的文件,然后将类型暴露出去,就可以让外界进行各种数据库操做了。
> models/user.js
var mongoose = require('mongoose');
var User = require('../schemas/user');
module.exports = mongoose.model('User', User);
(3)routes:看见名字就知道这个里面是对路由的各种操作,相当于Java里面的servlet要做的事情,进行页面的跳转和数据的传送。下面看routes的目录:
在这个文件夹下,index.js是最重要的,里面是所有路由的接口,其他的都是每个路由跳转所要执行的操作。下面的代码是index.js里的部分内容:
> routes/index.js
var login = require('./login');
var blog = require('./blog');
module.exports = function (app){
app.get('/bloglist', blog.getAllBlog); //跳到文章列表页
app.get('/home', function (req, res){ //跳到首页
res.render('index', {
title: '小静博客——首页',
});
});
};
app.post('/doLogin', login.checkLogin); //验证登录信息
可以看到我们传入了app参数,这个是express实例化的对象,所有http的get和post请求都是用app对象来完成的。
(4)static:里面存放的是所有静态资源,比如js,css还有图片等文件。
(5)views:里面存的是所有的html页面。
(6)app.js:这个无疑是express框架中最重要的了,是等个项目的入口文件,在这个项目中只有该文件的生命周期是直到关闭服务器,所以可见它的重要性。在这个文件中需要引入所要使用的:
- 各种中间件:用于设置session和cookie的express-session和cookie-parser,还有body-parser,用于处理
JSON和application/x-www-form-urlencoded 编码的数据。 - 驱动程序包:mongodb的驱动包mongoose;
- 页面的模板引擎:ejs;
连接并启动数据库,监听端口等都在这个入口文件中。如下代码所示:
> app.js
var express = require('express');
var ejs = require('ejs');
var bodyParser = require('body-parser');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var mongoose = require('mongoose');
//将路由文件引入
var route = require('./routes/index');
//设置端口
var port = process.env.PORT || 3000;
var app = express();
//设置试图的根目录
app.set('views', './views/pages');
//设置试图的模板引擎
app.engine('.html', ejs.__express);
app.set('view engine', 'html');
//设置静态资源路径
app.use(express.static('./static'));
// 解析 application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// 解析 application/json
app.use(bodyParser.json());
//设置session和cookie
app.use(cookieParser());
app.use(session({
secret: '12345',
name: 'testapp',
resave: false,
saveUninitialized: true,
}));
//监听端口
app.listen(port);
console.log("Server is runnng on " + port);
//连接mongodb数据库
mongoose.Promise = global.Promise; //不加这句会报错
mongoose.connect('mongodb://127.0.0.1/myblog');
mongoose.connection.on('open', function (){
console.log('Connected to Mongoose');
});
route(app); //初始化所有路由
三. 项目的难点
写这个项目最大的感受就是,node是异步的,和之前一直使用的java有很大区别,很容易出错,可是node页提供了很强大的机制,Promise,他让所有的异步操作看起来更像是顺序的,也让代码变得可读性更强了。下面是获得某条博客信息的具体代码,来看看Promise的魅力:
//获得某条博客的信息,并更新浏览次数
exports.getBlog = function (req, res){
var blogid = req.params.id;
var error = '';
var user = req.session.user || null;
Blog.findOne({_id: blogid}, function (err, blog){
if (blog == null){
error = '该文章被主人删除!';
res.render({
error: error
});
}else{
//更新文章阅读次数
var promise1 = updateLook_num(blogid);
//查找文章作者的信息
var promise2 = findUser(blog.authorid);
//查找该博客的所有评论信息
var promise3 = findReview(blogid);
//查看未读消息总数
var promise4 = message.totalUnreadMess(blog.authorid);
Promise.all([promise1, promise2, promise3, promise4]).then(function (result){
res.render('blogdetail', {
title: blog.title,
error: error,
blog: blog,
user: user,
author: result[1],
reviewlist: result[2],
totalmess: result[3],
});
}).catch(function (err){
console.log(err);
});
}
});
}
上面的每个promise对象都代表了一个异步操作,如果不适用Promise就会陷入代码嵌套的无底洞,那将会是灾难,可以有了Promise将每个异步操作都分开书写,然后在用all方法去执行,代码就很容易理解,可读性和可维护性都会大大提高。
四. 截图
附上自己的最终截图吧:
博客列表页
文章详情页
评论消息提醒页
在这篇博客中,我并没有多说代码如何编写,而是主要说了项目的架构,我想对大多数人来说明白项目的架构,就会有个整体的概念,心里就会有个模板,至于代码的具体实现就看自己的js功底了。
代码已上传至github:https://github.com/lwjcode/myblog
欢迎fork and star.