搭建
如果全局安装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/111 和 http://localhost:3000/users/id/111
首先在app.js中配置1
2var users = require('./routes/users');
app.use('/users', users);
然后配置routes路径下的users.js1
2
3
4
5
6
7
8
9
10
11
12
13var 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,可以将控制权转移到后面的规则
即执行完先定义的规则后会继续执行后面定义的规则
手动安装片段视图
由于网站中多页面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 可下载安装包
遇到该步骤时,
选择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
5module.exports = {
cookieSecret: 'microblogYooHannah',
db: 'microblog',
host: 'localhost',
};
新建models文件夹,并在里面新建文件db.js,内容如下:1
2
3
4
5var 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.js1
2
3
4
5
6
7
8
9var 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.js1
2
3
4
5
6
7
8
9
10
11var 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
4app.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.js1
2
3
4
5
6
7
8
9
10
11app.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>
<% } %>
它的功能是页面通知。
登录登出操作,状态判断;建立微博模型,处理微博发表操作
同样建立连接路由,写响应函数
处理首页登录前后状态
省略步骤可参考书籍
代码详见