Twitch 商城網(wǎng)站
介紹:
1、Node.js搭建的網(wǎng)站,采用Mongodb數(shù)據(jù)庫(kù)
2缺谴、后臺(tái)框架 借用了 express 窗骑,模板引擎使用的 ejs女责,對(duì)于數(shù)據(jù)庫(kù)的操作使用的是 mongoose
網(wǎng)站搭建流程
入口文件 app.js
我們來(lái)作一些修改,以上代碼實(shí)現(xiàn)了路由的功能创译,我們當(dāng)然可以不要 routes/index.js 文件抵知,把實(shí)現(xiàn)路由功能的代碼都放在 app.js 里,但隨著時(shí)間的推移 app.js 會(huì)變得臃腫難以維護(hù),這也違背了代碼模塊化的思想刷喜,所以我們把實(shí)現(xiàn)路由功能的代碼都放在 routes/index.js 里残制。官方給出的寫(xiě)法是在 app.js 中實(shí)現(xiàn)了簡(jiǎn)單的路由分配,然后再去 index.js 中找到對(duì)應(yīng)的路由函數(shù)掖疮,最終實(shí)現(xiàn)路由功能初茶。我們不妨把路由控制器和實(shí)現(xiàn)路由功能的函數(shù)都放到 index.js 里,app.js 中只有一個(gè)總的路由接口浊闪。
var routes = require('./routes/index');
//在執(zhí)行到錯(cuò)誤處理程序前 將 express實(shí)例 app 傳給 路由
routes(app);
routes/index.js 文件纺蛆,總的路由接口
module.exports = function(app) {
app.get('/', function (req, res) {
res.render('index', { title: 'Express' });
});
};
app.js 和 index.js 修改成這樣就達(dá)成了總路由接口的配置了!
路由規(guī)則
express 封裝了多種 http 請(qǐng)求方式规揪,我們主要只使用 get 和 post 兩種桥氏,即 app.get() 和 app.post()
app.get() 和 app.post() 的第一個(gè)參數(shù)都為請(qǐng)求的路徑,第二個(gè)參數(shù)為處理請(qǐng)求的回調(diào)函數(shù)猛铅,回調(diào)函數(shù)有兩個(gè)參數(shù)分別是 req 和 res字支,代表請(qǐng)求信息和響應(yīng)信息 。路徑請(qǐng)求及對(duì)應(yīng)的獲取路徑有以下幾種形式:這里就參考文檔
解析 :
- req.query: 處理 get 請(qǐng)求奸忽,獲取 get 請(qǐng)求參數(shù)
- req.params: 處理 /:xxx 形式的 get 或 post 請(qǐng)求堕伪,獲取請(qǐng)求參數(shù)
- req.body: 處理 post 請(qǐng)求,獲取 post 請(qǐng)求體
- req.param(): 處理 get 和 post 請(qǐng)求栗菜,但查找優(yōu)先級(jí)由高到低為 req.params→req.body→req.query
路徑規(guī)則還支持正則表達(dá)式欠雌,更多請(qǐng)查閱 Express 官方文檔 。
接下來(lái)自己添加一個(gè)路由規(guī)則做下測(cè)試吧疙筹!
模板引擎
什么是模板引擎
模板引擎(Template Engine)是一個(gè)將頁(yè)面模板和要顯示的數(shù)據(jù)結(jié)合起來(lái)生成 HTML 頁(yè)面的工具富俄。
如果說(shuō)上面講到的 express 中的路由控制方法相當(dāng)于 MVC 中的控制器的話,那模板引擎就相當(dāng)于 MVC 中的視圖而咆。
什么事ejs霍比?
ejs 是模板引擎的一種,也是我們這個(gè)教程中使用的模板引擎暴备,因?yàn)樗褂闷饋?lái)十分簡(jiǎn)單悠瞬,而且與 express 集成良好。
使用模板引擎
前面我們通過(guò)以下兩行代碼設(shè)置了模板文件的存儲(chǔ)位置和使用的模板引擎:
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
注意:我們通過(guò) express -e blog 只是初始化了一個(gè)使用 ejs 模板引擎的工程而已涯捻,比如 node_modules 下添加了 ejs 模塊浅妆,views 文件夾下有 index.ejs 。并不是說(shuō)強(qiáng)制該工程只能使用 ejs 不能使用其他的模板引擎比如 jade障癌,真正指定使用哪個(gè)模板引擎的是 app.set('view engine', 'ejs'); 凌外。
在 routes/index.js 中通過(guò)調(diào)用 res.render() 渲染模版,并將其產(chǎn)生的頁(yè)面直接返回給客戶端混弥。它接受兩個(gè)參數(shù)趴乡,第一個(gè)是模板的名稱,即 views 目錄下的模板文件名蝗拿,擴(kuò)展名 .ejs 可選晾捏。第二個(gè)參數(shù)是傳遞給模板的數(shù)據(jù)對(duì)象,用于模板翻譯哀托。
當(dāng)我們 res.render('index', { title: 'Express' }); 時(shí)惦辛,模板引擎會(huì)把 <%= title %> 替換成 Express,然后把替換后的頁(yè)面顯示給用戶仓手。
注意:我們通過(guò) app.use(express.static(path.join(__dirname, 'public'))) 設(shè)置了靜態(tài)文件目錄為 public 文件夾胖齐,所以上面代碼中的 href='/stylesheets/style.css' 就相當(dāng)于 href='public/stylesheets/style.css'
ejs 的標(biāo)簽系統(tǒng)非常簡(jiǎn)單,它只有以下三種標(biāo)簽:
- <% code %>:JavaScript 代碼嗽冒。
- <%= code %>:顯示替換過(guò) HTML 特殊字符的內(nèi)容呀伙。
- <%- code %>:顯示原始 HTML 內(nèi)容舅世。
注意: <%= code %> 和 <%- code %> 的區(qū)別日丹,當(dāng)變量 code 為普通字符串時(shí),兩者沒(méi)有區(qū)別逛钻。當(dāng) code 比如為 <h1>hello</h1> 這種字符串時(shí)贬蛙,<%= code %> 會(huì)原樣輸出 <h1>hello</h1>雨女,而 <%- code %> 則會(huì)顯示 H1 大的 hello 字符串。
我們可以在 <% %> 內(nèi)使用 JavaScript 代碼阳准。下面是 ejs 的官方示例:
The Data
supplies: ['mop', 'broom', 'duster']
The Template
<ul>
<% for(var i=0; i<supplies.length; i++) {%>
<li><%= supplies[i] %></li>
<% } %>
</ul>
The Result
<ul>
<li>mop</li>
<li>broom</li>
<li>duster</li>
</ul>
我們可以用上述三種標(biāo)簽實(shí)現(xiàn)頁(yè)面模板系統(tǒng)能實(shí)現(xiàn)的任何內(nèi)容氛堕。
頁(yè)面布局
這里我們不使用layout進(jìn)行頁(yè)面布局,而是使用更為簡(jiǎn)單靈活的include野蝇。include 的簡(jiǎn)單使用如下:
index.ejs
<%- include a %>
hello,world!
<%- include b %>
a.ejs
this is a.ejs
b.ejs
this is b.ejs
最終index.ejs會(huì)顯示
this is a.ejs
hello,world!
this is b.ejs
根據(jù)上面讼稚,我們具體初步的了解了一些nodejs、express一些特性绕沈,接下來(lái)正式開(kāi)始搭建多人博客乱灵。
搭建多人博客
功能分析
搭建一個(gè)簡(jiǎn)單的具有多人注冊(cè)、登錄七冲、發(fā)表文章痛倚、登出功能的博客。
設(shè)計(jì)目標(biāo)
未登錄:主頁(yè)左側(cè)導(dǎo)航顯示 home澜躺、login蝉稳、register,右側(cè)顯示已發(fā)表的文章掘鄙、發(fā)表日期及作者耘戚。
登陸后:主頁(yè)左側(cè)導(dǎo)航顯示 home、post操漠、logout收津,右側(cè)顯示已發(fā)表的文章饿这、發(fā)表日期及作者。
用戶登錄撞秋、注冊(cè)长捧、發(fā)表成功以及登出后都返回到主頁(yè)。
未登錄效果圖:
主頁(yè):
登錄頁(yè):
![登錄頁(yè)](https://github.com/nswbmw/N-blog/raw/master/public/images/1.7.jpg?raw=true)
注冊(cè)頁(yè):
![注冊(cè)頁(yè)](https://github.com/nswbmw/N-blog/raw/master/public/images/1.8.jpg?raw=true)
登錄后的效果圖:
主頁(yè):
![主頁(yè)](https://github.com/nswbmw/N-blog/raw/master/public/images/1.9.jpg?raw=true)
發(fā)表頁(yè):
![發(fā)表頁(yè)](https://github.com/nswbmw/N-blog/raw/master/public/images/1.10.jpg?raw=true)
注意:沒(méi)有登出頁(yè)吻贿,當(dāng)點(diǎn)擊 LOGOUT 后串结,退出登陸并返回到主頁(yè)。
路由規(guī)劃
我們已經(jīng)把設(shè)計(jì)的構(gòu)想圖貼出來(lái)了舅列,接下來(lái)的任務(wù)就是完成路由規(guī)劃了肌割。路由規(guī)劃,或者說(shuō)控制器規(guī)劃是整個(gè)網(wǎng)站的骨架部分帐要,因?yàn)樗幱谡麄€(gè)架構(gòu)的樞紐位置把敞,相當(dāng)于各個(gè)接口之間的粘合劑,所以應(yīng)該優(yōu)先考慮榨惠。
根據(jù)構(gòu)思的設(shè)計(jì)圖先巴,我們作以下路由規(guī)劃:
/ :首頁(yè)
/login :用戶登錄
/reg :用戶注冊(cè)
/post :發(fā)表文章
/logout :登出
我們要求 /login 和 /reg 只能是未登錄的用戶訪問(wèn),而 /post 和 /logout 只能是已登錄的用戶訪問(wèn)冒冬。左側(cè)導(dǎo)航列表則針對(duì)已登錄和未登錄的用戶顯示不同的內(nèi)容伸蚯。
修改 index.js 如下:
// 路由控制器和實(shí)現(xiàn)路由功能的函數(shù),都在這個(gè)文件里
module.exports = function(app){
// 主頁(yè)
app.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});
// 注冊(cè),跳轉(zhuǎn)注冊(cè)頁(yè)
app.get('/reg',function(req,res){
res.render('reg',{title:'注冊(cè)'});
});
// 注冊(cè)简烤,注冊(cè)操作
app.post('/reg',function(req,res){
});
// 登錄,跳轉(zhuǎn)登錄頁(yè)
app.get('/login',function(req,res){
res.render('login',{title:'登錄'});
});
// 登錄剂邮,登錄操作
app.post('/login',function(req,res){
});
// 發(fā)表,跳轉(zhuǎn)發(fā)表頁(yè)
app.get('/post',function(req,res){
res.render('post',{title:'發(fā)表'});
});
// 發(fā)表横侦,發(fā)表操作
app.post('/post',function(req,res){
});
// 注銷
app.get('/logout',function(req,res){
});
};
使用數(shù)據(jù)庫(kù)
MongoDB簡(jiǎn)介
MongoDB 是一個(gè)基于分布式文件存儲(chǔ)的 NoSQL(非關(guān)系型數(shù)據(jù)庫(kù))的一種挥萌,由 C++ 語(yǔ)言編寫(xiě),旨在為 WEB 應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案枉侧。MongoDB 支持的數(shù)據(jù)結(jié)構(gòu)非常松散引瀑,是類似 json 的 bjson 格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類型榨馁。MongoDB 最大的特點(diǎn)是他支持的查詢語(yǔ)言非常強(qiáng)大憨栽,其語(yǔ)法有點(diǎn)類似于面向?qū)ο蟮牟樵冋Z(yǔ)言,幾乎可以實(shí)現(xiàn)類似關(guān)系數(shù)據(jù)庫(kù)單表查詢的絕大部分功能翼虫,而且還支持對(duì)數(shù)據(jù)建立索引屑柔。
MongoDB 沒(méi)有關(guān)系型數(shù)據(jù)庫(kù)中行和表的概念,不過(guò)有類似的文檔和集合的概念珍剑。文檔是 MongoDB 最基本的單位掸宛,每個(gè)文檔都會(huì)以唯一的 _id 標(biāo)識(shí),文檔的屬性為 key/value 的鍵值對(duì)形式招拙,文檔內(nèi)可以嵌套另一個(gè)文檔唧瘾,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類型措译。集合是許多文檔的總和,一個(gè)數(shù)據(jù)庫(kù)可以有多個(gè)集合饰序,一個(gè)集合可以有多個(gè)文檔领虹。
更多有關(guān) MongoDB 的知識(shí)請(qǐng)參閱 《mongodb權(quán)威指南》或查閱:http://www.mongodb.org/
安裝MongoDB
安裝 MongoDB 很簡(jiǎn)單,去官網(wǎng)下載對(duì)應(yīng)系統(tǒng)的 MongoDB 壓縮包即可。解壓后將文件夾重命名為 mongodb菌羽,并在 mongodb 文件夾里新建 blog 文件夾作為我們博客內(nèi)容的存儲(chǔ)目錄掠械。進(jìn)入到 bin 目錄下:運(yùn)行:
./mongod --dbpath ../blog/
以上命令的意思是:設(shè)置 blog 文件夾作為我們工程的存儲(chǔ)目錄并啟動(dòng)數(shù)據(jù)庫(kù)由缆。
連接MongoDB
數(shù)據(jù)庫(kù)雖然安裝并啟動(dòng)成功了注祖,但我們需要連接數(shù)據(jù)庫(kù)后才能使用數(shù)據(jù)庫(kù)。怎么才能在 Node.js 中使用 MongoDB 呢均唉?我們使用官方提供的 node-mongodb-native 驅(qū)動(dòng)模塊是晨,打開(kāi) package.json,在 dependencies 中添加一行:
"mongodb": "1.4.15"
然后運(yùn)行 npm install 更新依賴的模塊舔箭,稍等片刻后 mongodb 模塊就下載并安裝完成了罩缴。
創(chuàng)建setting.js文件
接下來(lái)在工程的根目錄中創(chuàng)建 settings.js 文件,用于保存該博客工程的配置信息层扶,比如數(shù)據(jù)庫(kù)的連接信息箫章。我們將數(shù)據(jù)庫(kù)命名為 blog,因?yàn)閿?shù)據(jù)庫(kù)服務(wù)器在本地镜会,所以 settings.js 文件的內(nèi)容如下:
module.exports = {
cookieSecret: 'myblog',
db: 'blog',
host: 'localhost',
port: 27017
};
其中 db 是數(shù)據(jù)庫(kù)的名稱檬寂,host 是數(shù)據(jù)庫(kù)的地址,port是數(shù)據(jù)庫(kù)的端口號(hào)戳表,cookieSecret 用于 Cookie 加密與數(shù)據(jù)庫(kù)無(wú)關(guān)桶至,我們留作后用。
創(chuàng)建Models文件夾
接下來(lái)在根目錄下新建 models 文件夾匾旭,并在 models 文件夾下新建 db.js 镣屹,添加如下代碼:
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, settings.port),
{safe: true});
其中通過(guò) new Db(settings.db, new Server(settings.host, settings.port), {safe: true}); 設(shè)置數(shù)據(jù)庫(kù)名、數(shù)據(jù)庫(kù)地址和數(shù)據(jù)庫(kù)端口創(chuàng)建了一個(gè)數(shù)據(jù)庫(kù)連接實(shí)例价涝,并通過(guò) module.exports 導(dǎo)出該實(shí)例女蜈。這樣,我們就可以通過(guò) require 這個(gè)文件來(lái)對(duì)數(shù)據(jù)庫(kù)進(jìn)行讀寫(xiě)了色瘩。
打開(kāi) app.js鞭光,在 var routes = require('./routes/index'); 下添加:
var settings = require('./settings');
會(huì)話支持 session
express 也提供了會(huì)話中間件,默認(rèn)情況下是把用戶信息存儲(chǔ)在內(nèi)存中泞遗,但我們既然已經(jīng)有了 MongoDB惰许,不妨把會(huì)話信息存儲(chǔ)在數(shù)據(jù)庫(kù)中,便于持久維護(hù)史辙。為了使用這一功能汹买,我們需要借助 express-session 和 connect-mongo 這兩個(gè)第三方中間件佩伤,在 package.json 中添加:
"express-session": "1.9.1",
"connect-mongo": "0.4.1"
注意: 如報(bào)"error setting ttl index on collection : sessions"錯(cuò)誤,把"mongodb"&"connect-mongo"版本號(hào)更到最新晦毙。
在package.json修改 "mongodb":“2.0.42”生巡, “connect-mongo”:“0.8.2” 運(yùn)行npm install安裝模塊,打開(kāi)app.js,添加以下代碼:
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
app.use(session({
secret: settings.cookieSecret,
key: settings.db,//cookie name
cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},//30 days
store: new MongoStore({
db: settings.db,
host: settings.host,
port: settings.port
})
}));
注意: connect-mongo 最新版需要改成如:
store: new MongoStore({
url: 'mongodb://localhost/blog'
})
使用 express-session 和 connect-mongo 模塊實(shí)現(xiàn)了將會(huì)化信息存儲(chǔ)到mongoldb中见妒。secret 用來(lái)防止篡改 cookie孤荣,key 的值為 cookie 的名字,通過(guò)設(shè)置 cookie 的 maxAge 值設(shè)定 cookie 的生存期须揣,這里我們?cè)O(shè)置 cookie 的生存期為 30 天盐股,設(shè)置它的 store 參數(shù)為 MongoStore 實(shí)例,把會(huì)話信息存儲(chǔ)到數(shù)據(jù)庫(kù)中耻卡,以避免丟失疯汁。在后面的小節(jié)中,我們可以通過(guò) req.session 獲取當(dāng)前用戶的會(huì)話對(duì)象卵酪,獲取用戶的相關(guān)信息幌蚊。
實(shí)現(xiàn)注冊(cè)和登陸
我們已經(jīng)準(zhǔn)備好了數(shù)據(jù)庫(kù)訪問(wèn)和會(huì)話的相關(guān)信息,接下來(lái)我們完成用戶注冊(cè)和登錄功能溃卡。
頁(yè)面設(shè)計(jì)
首先我們來(lái)完成主頁(yè)溢豆、登錄頁(yè)和注冊(cè)頁(yè)的頁(yè)面設(shè)計(jì)。
主頁(yè):index.ejs
<%- include header %>
這是主頁(yè)
<%- include footer %>
登錄頁(yè):login.ejs
<%- include header %>
<form method="post">
用戶名: <input type="text" name="name"/><br /><br />
密 碼: <input type="password" name="password"/><br /><br />
<input type="submit" value="登錄"/>
<input type="reset" value="重置"/>
</form>
<%- include footer %>
注冊(cè)頁(yè): reg.ejs
<%- include header %>
<form method="post">
用戶名: <input type="text" name="name"/><br /><br />
密 碼: <input type="password" name="password"/><br /><br />
確認(rèn)密碼:<input type="password" name="password-repeat"/><br /><br />
郵 箱: <input type="email" name="email"/><br /><br />
<input type="submit" value="注冊(cè)"/>
<input type="reset" value="重置"/>
</form>
<%- include footer %>
到這里 啟動(dòng)我們的博客看看吧瘸羡!
實(shí)時(shí)更新組件
注意:每次我們更新代碼后漩仙,都需要手動(dòng)停止并重啟應(yīng)用,使用 supervisor 模塊可以解決這個(gè)問(wèn)題最铁,每當(dāng)我們保存修改的文件時(shí)讯赏,supervisor 都會(huì)自動(dòng)幫我們重啟應(yīng)用。通過(guò):
$ npm install -g supervisor
安裝 supervisor 冷尉。使用 supervisor 命令啟動(dòng) app.js:
$ supervisor app.js
頁(yè)面通知
接下來(lái)我們實(shí)現(xiàn)用戶的注冊(cè)和登陸漱挎,在這之前我們需要引入 flash 模塊來(lái)實(shí)現(xiàn)頁(yè)面通知(即成功與錯(cuò)誤信息的顯示)的功能。
什么事Flash雀哨?
我們所說(shuō)的 flash 即 connect-flash 模塊(https://github.com/jaredhanson/connect-flash)磕谅,flash 是一個(gè)在 session 中用于存儲(chǔ)信息的特定區(qū)域。信息寫(xiě)入 flash 雾棺,下一次顯示完畢后即被清除膊夹。典型的應(yīng)用是結(jié)合重定向的功能,確保信息是提供給下一個(gè)被渲染的頁(yè)面捌浩。
在 package.json 添加一行代碼:
"connect-flash": "0.1.1"
然后 npm install 安裝 connect-flash 模塊放刨。修改 app.js ,在 var settings = require('./settings'); 后添加:
var flash = require('connect-flash');
在 app.set('view engine', 'ejs'); 后添加:
app.use(flash());
現(xiàn)在我們就可以使用 flash 功能了尸饺。
注冊(cè)響應(yīng)
前面我們已經(jīng)完成了注冊(cè)頁(yè)进统,當(dāng)然現(xiàn)在點(diǎn)擊注冊(cè)是沒(méi)有效果的助币,因?yàn)槲覀冞€沒(méi)有實(shí)現(xiàn)處理 POST 請(qǐng)求的功能,下面就來(lái)實(shí)現(xiàn)它螟碎。
在 models 文件夾下新建 user.js眉菱,添加如下代碼:
// 處理 用戶注冊(cè) 和 登錄
// 引入 連接數(shù)據(jù)庫(kù)實(shí)例 外部文件
var mongodb = require('./db');
// 獲取用戶的信息
function User(user) {
this.name = user.name;
this.password = user.password;
this.email = user.email;
}
// 導(dǎo)出,發(fā)布出去
module.exports = User;
// 存儲(chǔ)用戶信息 prototype 原型
User.prototype.save = function(callback) {
// Scheme 要存入數(shù)據(jù)庫(kù)的用戶文檔
var user = {
name : this.name,
password : this.password,
email: this.email
};
// 打開(kāi)數(shù)據(jù)庫(kù)
mongodb.open(function(err,db) {
if(err) {
return callback(err);//錯(cuò)誤掉分,返回err信息
}
// 讀取 users 集合
db.collection('users',function (err,collection) {
if(err){
mongodb.close();
return callback(err);
}
// 將用戶數(shù)據(jù)插入 users 集合
collection.insert(user,{
safe : true
} , function(err,user) {
mongodb.close();
if(err) {
return callback(err);//錯(cuò)誤俭缓,返回err信息
}
callback(null,user[0]);//成功!err為null酥郭,并返回存儲(chǔ)后的用戶文檔
});
});
});
};
// 讀取用戶信息
User.get = function(name,callback) {
// 打開(kāi)數(shù)據(jù)庫(kù)
mongodb.open(function(err,db) {
if(err){
return callback(err);
}
// 讀取users 集合
db.collection('users',function(err,collection)
{
if(err) {
mongodb.close();
return callback(err);
}
// 查找用戶名(name 鍵)值為 name 的一個(gè)文檔
collection.findOne({name:name},function(err,user){
if(err) {
return callback(err);//失敾埂!返回錯(cuò)誤信息
}
callback(null,user);//成功褥民!返回查詢的用戶信息
});
});
});
};
我們通過(guò) User.prototype.save 實(shí)現(xiàn)了用戶信息的存儲(chǔ)季春,通過(guò) User.get 實(shí)現(xiàn)了用戶信息的讀取洗搂。
打開(kāi) index.js 消返,在最前面添加如下代碼:
var crypto = require('crypto'),
User = require('../models/user.js');
通過(guò) require() 引入 crypto 模塊和 user.js 用戶模型文件,crypto 是 Node.js 的一個(gè)核心模塊耘拇,我們用它生成散列值來(lái)加密密碼撵颊。
修改 index.js 中 app.post('/reg') 如下:
注意:我們把用戶信息存儲(chǔ)在了 session 里,以后就可以通過(guò) req.session.user 讀取用戶信息惫叛。
- req.body: 就是 POST 請(qǐng)求信息解析過(guò)后的對(duì)象倡勇,例如我們要訪問(wèn) POST 來(lái)的表單內(nèi)的 name="password" 域的值,只需訪問(wèn) req.body['password'] 或 req.body.password 即可嘉涌。
- res.redirect: 重定向功能妻熊,實(shí)現(xiàn)了頁(yè)面的跳轉(zhuǎn),更多關(guān)于 res.redirect 的信息請(qǐng)查閱:http://expressjs.com/api.html#res.redirect 仑最。
- User:在前面的代碼中扔役,我們直接使用了 User 對(duì)象。User 是一個(gè)描述數(shù)據(jù)的對(duì)象警医,即 MVC 架構(gòu)中的模型亿胸。前面我們使用了許多視圖和控制器,這是第一次接觸到模型预皇。與視圖和控制器不同侈玄,模型是真正與數(shù)據(jù)打交道的工具,沒(méi)有模型吟温,網(wǎng)站就只是一個(gè)外殼序仙,不能發(fā)揮真實(shí)的作用,因此它是框架中最根本的部分鲁豪。
接下來(lái)我們實(shí)現(xiàn)當(dāng)注冊(cè)成功返回主頁(yè)時(shí)潘悼,左側(cè)導(dǎo)航顯示 HOME 洋丐、POST 、LOGOUT 挥等,右側(cè)顯示 注冊(cè)成功友绝! 字樣,即添加 flash 的頁(yè)面通知功能肝劲。
修改 header.ejs迁客,將 <nav></nav> 修改如下:
<nav>
<span><a title="主頁(yè)" href="/">home</a></span>
<% if (user) { %>
<span><a title="發(fā)表" href="/post">post</a></span>
<span><a title="登出" href="/logout">logout</a></span>
<% } else { %>
<span><a title="登錄" href="/login">login</a></span>
<span><a title="注冊(cè)" href="/reg">register</a></span>
<% } %>
</nav>
在 <article> 后添加如下代碼:
<% if (success) { %>
<div><%= success %></div>
<% } %>
<% if (error) { %>
<div><%= error %> </div>
<% } %>
修改 index.js ,將 app.get('/') 修改如下:
app.get('/', function (req, res) {
res.render('index', {
title: '主頁(yè)',
user: req.session.user,
success: req.flash('success').toString(),
error: req.flash('error').toString()
});
});
將 app.get('reg') 修改如下:
app.get('/reg', function (req, res) {
res.render('reg', {
title: '注冊(cè)',
user: req.session.user,
success: req.flash('success').toString(),
error: req.flash('error').toString()
});
});
現(xiàn)在運(yùn)行我們的博客辞槐,注冊(cè)成功后顯示如下:
![注冊(cè)成功](https://github.com/nswbmw/N-blog/raw/master/public/images/1.13.jpg?raw=true)
這個(gè)時(shí)候訪問(wèn)別的就會(huì) 出現(xiàn)一個(gè) user is undefined掷漱。因?yàn)槠渌穆酚蛇€沒(méi)傳遞一個(gè)user 過(guò)去。
我們通過(guò)對(duì) session 的使用實(shí)現(xiàn)了對(duì)用戶狀態(tài)的檢測(cè)榄檬,再根據(jù)不同的用戶狀態(tài)顯示不同的導(dǎo)航信息卜范。
簡(jiǎn)單解釋一下流程:用戶在注冊(cè)成功后,把用戶信息存入 session 鹿榜,頁(yè)面跳轉(zhuǎn)到主頁(yè)顯示 注冊(cè)成功海雪! 的字樣。同時(shí)把 session 中的用戶信息賦給變量 user 舱殿,在渲染 index.ejs 文件時(shí)通過(guò)檢測(cè) user 判斷用戶是否在線奥裸,根據(jù)用戶狀態(tài)的不同顯示不同的導(dǎo)航信息。
success: req.flash('success').toString() 的意思是將成功的信息賦值給變量 success沪袭, error: req.flash('error').toString() 的意思是將錯(cuò)誤的信息賦值給變量 error 湾宙,然后我們?cè)阡秩?ejs 模版文件時(shí)傳遞這兩個(gè)變量來(lái)進(jìn)行檢測(cè)并顯示通知。
登錄與登出響應(yīng)
現(xiàn)在我們來(lái)實(shí)現(xiàn)用戶登錄的功能冈绊。
打開(kāi) index.js 侠鳄,將 app.post('/login') 修改如下:
app.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');//用戶不存在則跳轉(zhuǎn)到登錄頁(yè)
}
//檢查密碼是否一致
if (user.password != password) {
req.flash('error', '密碼錯(cuò)誤!');
return res.redirect('/login');//密碼錯(cuò)誤則跳轉(zhuǎn)到登錄頁(yè)
}
//用戶名密碼都匹配后,將用戶信息存入 session
req.session.user = user;
req.flash('success', '登陸成功!');
res.redirect('/');//登陸成功后跳轉(zhuǎn)到主頁(yè)
});
});
將 app.get('/login') 修改如下:
app.get('/login', function (req, res) {
res.render('login', {
title: '登錄',
user: req.session.user,
success: req.flash('success').toString(),
error: req.flash('error').toString()});
});
(這樣就不會(huì)出現(xiàn) 'user is not defined' 的錯(cuò)誤了)
接下來(lái)我們實(shí)現(xiàn)登出響應(yīng)死宣。修改 app.get('/logout') 如下:
app.get('/logout', function (req, res) {
req.session.user = null;
req.flash('success', '登出成功!');
res.redirect('/');//登出成功后跳轉(zhuǎn)到主頁(yè)
});
注意:通過(guò)把 req.session.user 賦值 null 丟掉 session 中用戶的信息伟恶,實(shí)現(xiàn)用戶的退出。
登錄后頁(yè)面顯示如下:
![登錄成功](https://github.com/nswbmw/N-blog/raw/master/public/images/1.14.jpg?raw=true)