My Little World

搭建博客步骤

搭建

如果全局安装express 使用npm install -g express 语句安装后,无法使用express命令
则先执行npm install express-generator -g
express在4.0之后,需要安装the executable(执行器express-generator)才能执行express命令
express –view=ejs microblog //在当前文件夹创建文件夹microblog,并在里面部署express
cd microblog //进入microblog
npm install //安装nodejs包
DEBUG=microblog:* npm start //运行
npm install -g supervisor //安装supervisor,监视代码改动
supervisor ./bin/www //运行,会提示输入rs重新开始,输入’rs’回车即可,
//这里就不用每次改完都去手动中断进程再重新开始

路由初步配置

匹配

打开app.js文件
var index = require(‘./routes/index’); //引入不同访问路径的回调函数所在文件
app.use(‘/‘, index); //为回调函数配置访问路径

如果要建立分支路径,可以在回调函数文件中配置相应分支路径的回调函数
假如我想访问http://localhost:3000/users/111http://localhost:3000/users/id/111
首先在app.js中配置

1
2
var users = require('./routes/users');
app.use('/users', users);

然后配置routes路径下的users.js

1
2
3
4
5
6
7
8
9
10
11
12
13
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/:id', function(req, res, next) {
res.send('USER:'+req.params.id);
});

router.get('/id/:id', function(req, res, next) {
res.send('USERID:'+req.params.id);
});

module.exports = router;

注意路径参数id的获取,在app.js配置时是访问路径的共有前缀,在users.js中获取的是分支前缀
深入链接

控制权转移

express 处理路由规则时,会优先匹配先定义的陆游规则,后面的规则被屏蔽
通过调用回调函数的第三个参数next,可以将控制权转移到后面的规则
即执行完先定义的规则后会继续执行后面定义的规则
node1

手动安装片段视图

由于网站中多页面head和footer相同,所以要建立模板文件,然后让其他页面文件来来填充基于这种处理方法
express 4.x需要手动安装partials
npm install express-partials
在app.js中注册
var partials = require(‘express-partials’);
app.use(partials());

引入bootstrap 和 JQuery

http://twitter.github.com/bootstrap/下载bootstrap.zip,
将 img 目录复制到工程 public 目录下,
将 bootstrap.css、bootstrap-responsive.css 复制到 public/stylesheets 中,
将 bootstrap.js 复制到 public/javascripts 目录中,
然后从http://jquery.com/下载一份最新版的 jquery.js 也放入 public/javascripts 目录中。

界面

用.ejs文件当html文件,
ejs 的标签系统只有以下3种标签。
 <% code %>: JavaScript 代码。
 <%= code %>:显示替换过 HTML 特殊字符的内容。
 <%- code %>:显示原始 HTML 内容。
新建layout.ejs 做模板文件 ,调整index.ejs内容做首页填充内容,访问 http://localhost:3000/ 查看效果

MongoDB 数据库

安装

选用 MongoDB 作为网站的数据库系统
http://dl.mongodb.org/dl/win32/x86_64 可下载安装包
遇到该步骤时,
mongodb.png
选择custom可以自定义安装路径
安装完成后,在bin所在的文件夹,与bin同级建立data文件夹,然后cmd到bin文件夹,执行
mongod –dbpath data文件夹路径(例:D:\MongoDB\data)
执行完最后一行出现:
2017-03-12T13:16:29.286+0800 I NETWORK [thread1] waiting for connections on por
t 27017
浏览器输入 http://localhost:27017/ 可以看到显示信息为
It looks like you are trying to access MongoDB over HTTP on the native driver port.
说明安装完成

使用

修改package.json,dependencies中增加 “mongodb”: “>= 0.9.9”
npm install //更新依赖模块
在与app.js同级目录下新建settings.js,内容如下:

1
2
3
4
5
module.exports = {
cookieSecret: 'microblogYooHannah',
db: 'microblog',
host: 'localhost',
};

新建models文件夹,并在里面新建文件db.js,内容如下:

1
2
3
4
5
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});

修改package.json,dependencies中增加 “connect-mongo”: “>= 0.1.7”
npm install更新依赖模块
修改app.js

1
2
3
4
5
6
7
8
9
var MongoStore = require('connect-mongo');
var settings = require('./settings');

app.use(express.session({
secret: settings.cookieSecret,
store: new MongoStore({
db: settings.db
})
}));

由于session不再绑定在express上,这里会报错,所以要单独安装session
npm install express-session
修改app.js

1
2
3
4
5
6
7
8
9
10
11
var session    = require('express-session');
var MongoStore = require('connect-mongo')(session);
var settings = require('./settings');


app.use(session({
secret: settings.cookieSecret,
store: new MongoStore({
url: 'mongodb://localhost/db'//链接数据库地址
})
}));

如出现错误:
MongoError: failed to connect to server [localhost:27017] on first connect
可能是没有运行刚才安装的MongoDB,这时要回到cmd,执行
mongod –dbpath data文件夹路径(例:D:\MongoDB\data)
如出现以下提醒:
express-session deprecated undefined resave option;
express-session deprecated undefined saveUninitialized option;
则补充上这两个配置参数

1
2
3
4
app.use(session({
resave: false, //添加 resave 选项
saveUninitialized: true, //添加 saveUninitialized 选项
}));

注册页面

在view中新建reg.ejs,内容如下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<form class="form-horizontal" method="post">
<fieldset>
<legend>用户注册</legend>
<div class="control-group">
<label class="control-label" for="username">用户名</label>
<div class="controls">
<input type="text" class="input-xlarge" id="username" name="username">
<p class="help-block">你的账户名称,用于登录和显示。 </p>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">口令</label>
<div class="controls">
<input type="password" class="input-xlarge" id="password" name="password">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password-repeat">重复输入口令</label>
<div class="controls">
<input type="password" class="input-xlarge" id="password-repeat" name="password-repeat">
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">注册</button>
</div>
</fieldset>
</form>

在app.js和routes/index中增加访问路径和响应函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//app.js
var router = require('./routes/index');//路由
var app = express();
app.use('/', router);
app.use('/reg',router );

//routes/index.js
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: '首页' });
});

router.get('/reg', function(req, res, next) {
res.render('reg', { title: '用户注册' });
});

router.post('/reg', function(req, res) {
//检验用户两次输入的口令是否一致
if (req.body['password-repeat'] != req.body['password']) {
req.flash('error', '两次输入的口令不一致');
return res.redirect('/reg');
}
//生成口令的散列值
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 already exists.';
if (err) {
req.flash('error', err);
return res.redirect('/reg');
}
//如果不存在则新增用户
newUser.save(function(err) {
if (err) {
req.flash('error', err);
return res.redirect('/reg');
}
req.session.user = newUser;
req.flash('success', '注册成功');
res.redirect('/');
});
});
});
module.exports = router;

响应函数中的User是用户模型,在models中创建user.js,再引入到routes/index
响应函数会出现
1.title is not defined的问题
解决办法就是将views/layout.ejs的title换成locals.title
2.req.flash会报错说req.flash is not a function,则
npm install connect-flash
app.js修改:
var flash = require(‘connect-flash’);
app.use(flash());
这样所有的req就可以使用flash()函数
3.crypto没有被定义
npm install crypto
routes/index.js引入
var crypto = require(‘crypto’);

视图交互

实现不同登录状态下页面呈现不同内容的功能,创建动态视图助手
app.js

1
2
3
4
5
6
7
8
9
10
11
app.use(function(req,res,next){
res.locals.user=req.session.user;

var err = req.flash('error');
var success = req.flash('success');

res.locals.error = err.length ? err : null;
res.locals.success = success.length ? success : null;

next();
});

放在路由配置前面
接下来,修改 layout.ejs中的导航栏部分,为已登入用户和未登入用户显示不同的信息

1
2
3
4
5
6
7
8
9
<ul class="nav">
<li class="active"><a href="/">首页</a></li>
<% if (!user) { %>
<li><a href="/login">登入</a></li>
<li><a href="/reg">注册</a></li>
<% } else { %>
<li><a href="/logout">登出</a></li>
<% } %>
</ul>

在 container 中,<%- body %>之前加入:

1
2
3
4
5
6
7
8
9
10
<% if (success) { %>
<div class="alert alert-success">
<%= success %>
</div>
<% } %>
<% if (error) { %>
<div class="alert alert-error">
<%= error %>
</div>
<% } %>

它的功能是页面通知。

登录登出操作,状态判断;建立微博模型,处理微博发表操作

同样建立连接路由,写响应函数

处理首页登录前后状态

省略步骤可参考书籍
代码详见