項目實戰(zhàn)(連載):基于Angular2+Mongodb+Node技術實現(xiàn)的多用戶博客系統(tǒng)教程(5)

本章主要講什么(一句話)兴蒸?

《項目實戰(zhàn):基于Angular2+Mongodb+Node技術實現(xiàn)的多用戶博客系統(tǒng)教程(5)》

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?-- Express框架代碼培析&優(yōu)化配置

一上枕、前言

? ? ?上一章,我們給大家講解了項目實戰(zhàn)所必須的基礎環(huán)境搭建與必備知識儲備技能,同時對Express框架進行了快速搭建荡灾,本章我們將會對Express框架給大家做一個詳細的培析,同時對本框架結(jié)合我們的項目需求做一優(yōu)化重構(gòu)哮内。

PS--不過后繼想改變一下嚴肅的風格圈暗,采用一些好玩的圖片配合,希望能讓枯燥的編程能夠產(chǎn)生點樂趣 :)

二缘挽、Express框架詳解

2.1瞄崇、工程結(jié)構(gòu)

2.1.1、工程結(jié)構(gòu)-工程目錄

生成的工程目錄里面都有什么壕曼,打開我們的blog文件夾苏研,里面如圖所示:

說明如下:

app.js:啟動文件,或者說入口文件

package.json:存儲著工程的信息及模塊依賴腮郊,當在dependencies中添加依賴的模塊時摹蘑,運行npm install,npm會檢查當前目錄下的package.json伴榔,并自動安裝所有指定的模塊

node_modules:存放package.json中安裝的模塊纹蝴,當你在package.json添加依賴的模塊并安裝后,存放在這個文件夾下

public:存放image踪少、css塘安、js等文件

routes:存放路由文件

views:存放視圖文件或者說模版文件

bin:存放可執(zhí)行文件

2.1.2、工程結(jié)構(gòu)-app.js

打開app.js,讓我們看看里面究竟有什么:

核心代碼我以注釋的方式解釋援奢!

// require()加載了express兼犯、path等模塊,以及routes文件夾下

//的index. js和users.js路由文件

var express = require('express');

var path = require('path');

var favicon = require('serve-favicon');

var logger = require('morgan');

var cookieParser = require('cookie-parser');

var bodyParser = require('body-parser');

var routes = require('./routes/index');

var users = require('./routes/users');

var app = express();//生成一個express實例app。

/*設置views文件夾為存放視圖文件的目錄,即存放模板文件的地方

,__dirname為全局變量,存儲當前正在執(zhí)行的腳本所在的目錄集漾。*/

app.set('views', path.join(__dirname, 'views'));

//設置視圖模板引擎為ejs

app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public

//設置/public/favicon.ico為favicon圖標切黔。

//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

app.use(logger('dev')); //加載日志中間件

app.use(bodyParser.json()); //加載解析json的中間件

app.use(bodyParser.urlencoded({ extended: false })); //加載解析urlencoded請求體的中間件

app.use(cookieParser()); //加載解析cookie的中間件

app.use(express.static(path.join(__dirname, 'public'))); //設置public文件夾為存放靜態(tài)文件的目錄。

//路由控制器

app.use('/', routes);

app.use('/users', users);

// catch 404 and forward to error handler

//捕獲404錯誤具篇,并轉(zhuǎn)發(fā)到錯誤處理器

app.use(function(req, res, next) {

var err = new Error('Not Found');

err.status = 404;

next(err);

});

// error handlers

// development error handler

// will print stacktrace

//開發(fā)環(huán)境下的錯誤處理器纬霞,將錯誤信息渲染error模版并顯示到瀏覽器中

if (app.get('env') === 'development') {

app.use(function(err, req, res, next) {

res.status(err.status || 500);

res.render('error', {

message: err.message,

error: err

});

});

}

// production error handler

// no stacktraces leaked to user

//生產(chǎn)環(huán)境下的錯誤處理器,將錯誤信息渲染error模版并顯示到瀏覽器中

app.use(function(err, req, res, next) {

res.status(err.status || 500);

res.render('error', {

message: err.message,

error: {}

});

});

//導出app實例供其他模塊調(diào)用

module.exports = app;

2.1.3驱显、工程結(jié)構(gòu)-bin/www文件

打開bin目錄下的www文件诗芜,內(nèi)容如下:


#!/usr/bin/env node

/**

* Module dependencies.

*/

var app = require('../app');

var debug = require('debug')('blog:server');

var http = require('http');

/**

* Get port from environment and store in Express.

*/

var port = normalizePort(process.env.PORT || '3000');

app.set('port', port);

/**

* Create HTTP server.

*/

var server = http.createServer(app);

/**

* Listen on provided port, on all network interfaces.

*/

server.listen(port);

server.on('error', onError);

server.on('listening', onListening);

瞳抓。。伏恐。孩哑。


上述代碼解釋如下:

(1) #!/usr/bin/env node:表明是node可執(zhí)行文件。

(2) var debug =require('debug')('blog:server')

:引入debug模塊翠桦,打印調(diào)試日志横蜒。

(3) var app = require('../app’):引入我們上面導出的app實例。

(4) app.set('port', process.env.PORT || 3000):設置端口號销凑。

(5) var server = http.createServer(app); server.listen(port);

server.on('error', onError); server.on('listening',onListening);

啟動工程并監(jiān)聽3000端口

2.1.4丛晌、工程結(jié)構(gòu)-routes/index.js文件

再看routes/index.js文件:

var express = require('express');

var router = express.Router();

/* GET home page. */

router.get('/', function(req, res, next) {

res.render('index', { title: 'Express' });

});

module.exports = router;

生成一個路由實例用來捕獲訪問主頁的GET請求,導出這個路由并在app.js中通過app.use('/', routes);加載闻鉴。這樣茵乱,當訪問主頁時,就會調(diào)用res.render('index', { title: 'Express' });渲染views/index.ejs模版并顯示到瀏覽器中孟岛。

我們再看看views/index.ejs文件:

在渲染模板時我們傳入了一個變量title值為express字符串瓶竭,模板引擎會將所有<%= title %>替換為express,然后將渲染后生成的html顯示到瀏覽器中渠羞,如上圖所示

至此斤贰,我們知道了如何創(chuàng)建一個Express工程并啟動它,了解了工程的大體結(jié)構(gòu)和運作流程!

2.2次询、路由控制

2.2.1荧恍、工作原理

routes/index.js中有以下代碼:

router.get('/', function(req, res){

res.render('index', { title: 'Express' });

});

這段代碼的意思是當訪問主頁時,調(diào)用ejs模板引擎屯吊,來渲染index.ejs模版文件(即將title變量全部替換為字符串Express)送巡,生成靜態(tài)頁面并顯示在瀏覽器中。

我們來作一些修改盒卸,以上代碼實現(xiàn)了路由的功能骗爆,我們當然可以不要routes/index.js文件,把實現(xiàn)路由功能的代碼都放在app.js里蔽介,但隨著時間的推移app.js會變得臃腫難以維護摘投,這也違背了代碼模塊化的思想,所以我們把實現(xiàn)路由功能的代碼都放在routes/index.js里虹蓄。官方給出的寫法是在app.js中實現(xiàn)了簡單的路由分配犀呼,然后再去index.js中找到對應的路由函數(shù),最終實現(xiàn)路由功能薇组。我們不妨把路由控制器和實現(xiàn)路由功能的函數(shù)都放到index.js里外臂,app.js中只有一個總的路由接口。

最終將app.js修改為:

PS:注意加粗部分律胀!


……

var http = require('http');

……

var routes = require('./routes/index');

var app = express();

app.set('port', process.env.PORT || 3000);

app.set('views', path.join(__dirname, 'views'));

app.set('view engine', 'ejs');

….

app.use(cookieParser());

app.use(express.static(path.join(__dirname, 'public')));

routes(app);

http.createServer(app).listen(app.get('port'),function(){

console.log('服務器已啟動专钉,監(jiān)聽端口:%s',app.get('port'));

});

//app.use('/', routes);

//app.use('/users', users);

// catch 404 and forward to error handler

app.use(function(req, res, next) {

…..


<%= title %>

修改index.js如下:

module.exports = function(app) {

app.get('/', function (req, res) {

res.render('index', { title: 'Express' });

});

};

現(xiàn)在挑童,再運行你的app累铅,你會發(fā)現(xiàn)主頁毫無二致跃须。這里我們在routes/index.js中通過module.exports導出了一個函數(shù)接口,在app.js中通過require加載了index.js然后通過routes(app)調(diào)用了index.js導出的函數(shù)娃兽。

同時刪除掉:bin目錄及目錄下的www文件

2.2.2菇民、路由規(guī)則

? 通過Requre獲取數(shù)據(jù)

express封裝了多種http請求方式,我們主要只使用get和post兩種投储,即app.get()和app.post()第练。

app.get()和app.post()的第一個參數(shù)都為請求的路徑,第二個參數(shù)為處理請求的回調(diào)函數(shù)玛荞,回調(diào)函數(shù)有兩個參數(shù)分別是req和res娇掏,代表請求信息和響應信息 。路徑請求及對應的獲取路徑有以下幾種形式:

方式一勋眯、req.query

// GET /search?q=fwytech+ferret

req.query.q

// => "fwytech ferret"

// GET /shoes?order=desc&color=blue& type=converse

req.query.order

// => "desc"

req.query.shoe.color

// => "blue"

req.query.shoe.type

// => "converse"

方式二婴梧、req.body

// POST user[name]=fwytech&user[email]=fwytech@126.com

req.body.user.name

// => "fwytech"

req.body.user.email

// => "fwytech@126.com"

// POST { "name": "fwytech" }

req.body.name

// => "fwytech"

方式三、req.params

// GET /user/tj

req.params.name

// => "tj"

// GET /file/javascripts/jquery.js

req.params[0]

// => "javascripts/jquery.js"

方式四客蹋、req.param(name)

// ?name=tobi

req.param('name')

// => "tobi"

// POST name=tobi

req.param('name')

// => "tobi"

// /user/tobifor/user/:name

req.param('name')

// => "tobi"

不難看出:

·req.query: 處理get請求塞蹭,獲取get請求參數(shù)

·req.params: 處理/:xxx形式的get或post請求,獲取請求參數(shù)

·req.body: 處理post請求讶坯,獲取post請求體

·req.param(): 處理get和post請求番电,但查找優(yōu)先級由高到低為req.params→req.body→req.query

路徑規(guī)則還支持正則表達式,更多請查閱:http://expressjs.com/en/api.html

2.2.3辆琅、路由規(guī)則添加路由規(guī)則

請在Node命令提示符下將目錄定位至你的node-blog目錄下:

> node app

啟動node服務器!

再次打開瀏覽器:健入http://localhost:3000,如果一切正常將會顯示如下:

當我們訪問localhost:3000/hello這種不存在的頁面時就會顯示:

這是因為不存在/hello的路由規(guī)則漱办,而且它也不是一個public目錄下的文件,所以express返回了404 Not Found的錯誤婉烟。下面我們來添加這條路由規(guī)則娩井,使得當訪問localhost:3000/hello時,頁面顯示hello,world!

注意:以下修改僅用于測試隅很,看到效果后再把代碼還原回來撞牢。

修改index.js,在app.get('/')函數(shù)后添加一條路由規(guī)則:

app.get('/hello', function (req, res) {

res.send('hello,world!');

});

重啟之后叔营,訪問localhost:3000/hello頁面顯示如下:

三屋彪、后述

? ?《基于Angular2+Mongodb+Node技術實現(xiàn)的多用戶博客系統(tǒng)》正在連載中,明天我將為大家推出【第六章:項目需求分析&路由歸劃&MongoDB配置】绒尊,歡迎各位繼續(xù)關注~

? ? 搜索并關注“風舞煙”的簡書專欄畜挥、頭條號、微信公眾號婴谱、 企鵝媒體平臺蟹但,你可以定期收到關于簡書專欄的最新動態(tài)以及IT前沿最新技術的高質(zhì)量經(jīng)驗文章躯泰、視頻分享。

? ? 謝謝大家的支持华糖,歡迎大家留言交流麦向。

本章代碼下載:http://pan.baidu.com/s/1nu6EIMH

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市客叉,隨后出現(xiàn)的幾起案子诵竭,更是在濱河造成了極大的恐慌,老刑警劉巖兼搏,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卵慰,死亡現(xiàn)場離奇詭異,居然都是意外死亡佛呻,警方通過查閱死者的電腦和手機裳朋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吓著,“玉大人鲤嫡,你說我怎么就攤上這事∫勾#” “怎么了泛范?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長紊撕。 經(jīng)常有香客問我罢荡,道長,這世上最難降的妖魔是什么对扶? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任区赵,我火速辦了婚禮,結(jié)果婚禮上浪南,老公的妹妹穿的比我還像新娘笼才。我一直安慰自己,他們只是感情好络凿,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布骡送。 她就那樣靜靜地躺著,像睡著了一般絮记。 火紅的嫁衣襯著肌膚如雪摔踱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天怨愤,我揣著相機與錄音派敷,去河邊找鬼。 笑死,一個胖子當著我的面吹牛篮愉,可吹牛的內(nèi)容都是我干的腐芍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼试躏,長吁一口氣:“原來是場噩夢啊……” “哼猪勇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起冗酿,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤埠对,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后裁替,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡貌笨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年弱判,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锥惋。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡昌腰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膀跌,到底是詐尸還是另有隱情遭商,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布捅伤,位于F島的核電站劫流,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏丛忆。R本人自食惡果不足惜祠汇,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望熄诡。 院中可真熱鬧可很,春花似錦、人聲如沸凰浮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袜茧。三九已至菜拓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惫周,已是汗流浹背尘惧。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留递递,地道東北人喷橙。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓啥么,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贰逾。 傳聞我的和親對象是個殘疾皇子悬荣,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容