项目实战-心情日记
【例16.1】制作网站—心情日记。(实例位置:资源包\源码\16\01)
本节将根据上面所学的相关内容,制作一个简单的网站—心情日记,该网站可以完成日记的编写、展示、修改和删除功能,另外还实现了登录、退出的功能,如图 16.31 所示。

由于篇幅有限,书中主要对网站功能的核心代码进行重点讲解,其他功能代码,可以查看资源包中的源代码。 |
Node.js中的mongojs模块
mongojs
是一个出色小巧的 Node.js 包,使用它可以很方便地在 Node.js 应用中访问 MongoDB
数据库。要使用它,首先需要使用下面命令进行安装:
npm install mongojs
bash
安装 mongojs
模块后,如果要使用它,需要用 require()
方法引入,代码如下:
var mongojs=require('mongojs')
javascript
mongojs
模块中提供了 connect(databaseUrl, collections)
方法来创建数据库连接对象。其中,databaseUrl
参数用来设置要连接的 MongoDB
数据库名称,collections
参数用来指定 MongoDB
数据库中的集合。
使用 connect()
方法创建的数据库连接对象可以调用 MongoDB
数据库的操作方法实现相应功能。比如,下面代码在 Node.js 程序中使用 mongojs
模块查询名称为 “mingrisoft” 的 MongoDB
数据库的 products
集合中的所有信息:
var mongojs=require('mongojs');
var db=mongojs.connect('mingrisoft', ['products']);
db.products.find()
javascript
初始化数据
心情日记项目的名称为 diary
,其项目结构如图 16.32 所示。

在运行本程序时,如果提示找不到模块,需要使用 |
打开系统的 “命令提示符” 对话框,通过 mongo
命令进入 MongoDB
数据库,创建 blog
数据库,并创建 post
和 user
两个集合,同时向 user
集合中添加默认的账户,账户名和密码分别是 admin
和 admin
。具体代码如下:
//创建数据库,添加管理员
use blog
db.createCollection('post')
db.createCollection('user')
db.user.save({ user: 'admin', pass: 'admin'})
javascript
在 MongoDB
中执行以上 4 条语句的效果如图 16.33 所示。

主页的实现
心情日记网站的主要功能是在 app.js
文件中实现的,该文件中首先引入相应的模块,并指定使用 MongoDB
数据库,代码如下:
var express = require('express')
, gzippo = require('gzippo')
, routes = require('./routes')
, crypto = require('crypto')
, moment = require('moment')
, cluster = require('cluster')
,path = require('path')
, os = require('os');
var mongojs=require('mongojs');
var db=mongojs('blog', ['post', 'user']);
javascript
在路由配置部分,当用户输入监听地址进行访问时,会自动链接到 index.jade
文件。代码如下:
//配置路由
app.get('/', function(req, res) {
var fields = { subject: 1, body: 1, tags: 1, created: 1, author: 1 };
db.post.find({ state: 'published'}, fields).sort({ created: -1}, function(err, posts) {
if (!err && posts) {
res.render('index.jade', { title: '心情日记', postList: posts });
}
});
});
javascript
index.jade
文件中使用 jade
模块语法,主要显示导航栏和所有的日记信息。代码如下:
mixin blogPost(post)
div.span6
a(href="/post/#{post._id}")
h3 #{post.subject}
p #{post.body.substr(0, 250) + '...'}
p#info
div.tags
for tag in post.tags
strong
a(href="#") #{tag}
div.post-time
em #{moment(post.created).format('YYYY-MM-DD HH:mm:ss')}
p
a(class="btn btn-small",href="/post/#{post._id}") 阅读更多 »
div.hero-unit
h1 心情日记
p 欢迎来到我的心情日记,这里有我最近的动态、想法和心情......
!=partial('alert', flash)
div
- for (var i = 0; i < postList.length; i++)
div.row
mixin blogPost(postList[i])
- if (i + 1 < postList.length)
mixin blogPost(postList[++i])
bash
添加日记
在 app.js
文件中实现添加日记功能时,首先通过 get()
方法监听 url
为 /post/add
的路径,当用户访问该路径时,将 add.jade
文件返回给客户端,并使用 insert()
方法将用户提交的信息添加到数据库中。关键代码如下:
app.get('/post/add', isUser, function(req, res) {
res.render('add.jade', { title: '添加新的日记 '});
});
app.post('/post/add', isUser, function(req, res) {
var values = {
subject: req.body.subject
, body: req.body.body
, tags: req.body.tags.split(',')
, state: 'published'
, created: new Date()
, modified: new Date()
, comments: []
, author: {
username: req.session.user.user
}
};
db.post.insert(values, function(err, post) {
console.log(err, post);
res.redirect('/');
});
});
javascript
add.jade
文件是客户端添加日记页面。在 add.jade
文件中,使用 jade
语法将添加日记的表单信息显示出来,并且其访问请求方式为 post
方式,因此在单击 “添加” 按钮时,会将表单中输入的信息提交服务器。add.jade
文件中的代码如下:
form(class="form-horizontal",name="add-post",method="post",action="/post/add")
fieldset
legend 添加新的日记
div.control-group
label.control-label 标题:
div.controls
input(type="text",name="subject",class="input-xlarge")
div.control-group
label.control-label 内容:
div.controls
textarea(name="body", rows="10", cols="30")
div.control-group
label.control-label 标签:
div.controls
input(type="text",name="tags",class="input-xlarge")
div.form-actions
input(type="submit",value="添加",name="post",class="btn btn-primary")
javascript
添加日记页面效果如图 16.34 所示。

修改日记
在 app.js
文件中实现修改日记功能时,使用 app
对象的 get
方法监听 url
是 /post/edit/:postid
的路径地址,将 edit.jade
返回给客户端,然后在 app
对象的 post
方法中使用 update
方法更新数据库中对应 id
的数据。关键代码如下:
app.get('/post/edit/:postid', isUser, function(req, res) {
res.render('edit.jade', { title: '修改日记', blogPost: req.post } );
});
app.post('/post/edit/:postid', isUser, function(req, res) {
db.post.update({ _id: db.ObjectId(req.body.id) }, {
$set: {
subject: req.body.subject
, body: req.body.body
, tags: req.body.tags.split(',')
, modified: new Date()
}
},
function(err, post) {
if (!err) {
req.flash('info', '日记修改成功!');
}
res.redirect('/');
});
});
javascript
edit.jade
文件是客户端的修改日记信息页面,该文件中使用 jade
语法根据指定 id
将日记相关的信息显示在相应的表单中,而其访问请求方式为 post
方式,因此在单击 “修改” 按钮时,会将表单中的信息提交服务器。edit.jade
文件中的代码如下:
form(class="form-horizontal",name="edit-post",method="post",action="/post/edit/#{blogPost._id}")
fieldset
legend 编辑日记 ##{blogPost._id}
div.control-group
label.control-label 标题:
div.controls
input(type="text",name="subject",class="input-xlarge span6",value="#{blogPost.subject}")
div.control-group
label.control-label 内容:
div.controls
textarea(name="body",rows="10",cols="30",class="span6") #{blogPost.body}
div.control-group
label.control-label 标签:
div.controls
input(type="text",name="tags",class="input-xlarge",value="#{blogPost.tags.join(',')}")
input(type="hidden",name="id",value="#{blogPost._id}")
div.form-actions
input(type="submit",value="修改",name="edit",class="btn btn-primary")
javascript
运行程序,首先在心情日记网站首页单击某一条日记的标题,进入其详细信息页面,然后单击右下角的 “修改” 超链接,如图16.35所示,即可跳转到修改日记页面,如图 16.36 所示,在该页面中对日记信息进行修改后,单击 “修改” 按钮即可。


删除日记
在 app.js
文件中实现删除日记功能时,使用 MongoDB
中的 remove
方法将数据库中对应 id
的数据删除即可。关键代码如下:
app.get('/post/delete/:postid', isUser, function(req, res) {
db.post.remove({ _id: db.ObjectId(req.params.postid) }, function(err, field) {
if (!err) {
req.flash('error', '日记删除成功');
}
res.redirect('/');
});
});
javascript
运行程序,首先在心情日记网站首页单击某一条日记的标题,进入其详细信息页面,如图 16.37 所示,然后单击右下角的 “删除” 超链接,即可删除指定的日记。

用户登录与退出
在 app.js
文件中实现登录与退出功能时,会提交 url
为 /login
的地址,然后在通过 post
方法监听到该地址的请求后,会接收用户提交的用户名和密码信息,使用 mongojs
模块的 findOne
方法判断是否能够找到相应的用户名和密码,如果找到,则记录登录用户,并跳转到首页,否则,停留在登录页面。关键代码如下:
//登录
app.get('/login', function(req, res) {
res.render('login.jade', {
title: 'Login user'
});
});
app.get('/logout', isUser, function(req, res) {
req.session.destroy();
res.redirect('/');
});
app.post('/login', function(req, res) {
var select = {
user: req.body.username
, pass: req.body.password
};
db.user.findOne(select, function(err, user) {
if (!err && user) {
//判断用户登录的session
req.session.user = user;
res.redirect('/');
} else {
//如果未登录的话,则停留在登录页面
res.redirect('/login');
}
});
});
javascript
login.jade
文件是客户端的用户登录页面,该页面中使用 form
表单提交用户的登录信息,提交方式为 post
,提交 action
是 /login
,这样就可以在 app.js
的 post
方法中接收到用户提交的登录信息,进而判断是否登录成功。login.jade
文件中的代码如下:
form(class="form-horizontal",name="login-form",method="post",action="/login") fieldset legend 请输入登录信息 div.control-group label.control-label 账户: div.controls input(type="text",name="username",class="input-xlarge") div.control-group label.control-label 密码: div.controls input(type="password",name="password",class="input-xlarge") div.form-actions input(type="submit",value="登录",name="login",class="btn btn-primary")
html
登录页面效果如图 16.38 所示。
