前言
最近同事推薦了一個不錯的網址:https://github.com/nswbmw/N-blog/wiki/_pages
里面的教程很是詳細,我們現在跟着他的節奏學習下NodeJS,一個簡單的博客
我們這次來個過年七天樂......看看能不能nodeJS來個入門
讓nodeJS跑起來
第一步當然是安裝nodeJS環境了,現在windows安裝nodeJS比較快了,直接下載即可:
http://www.nodejs.org/download/
這里根據需要下載,下載完成后直接下一步下一步即可,完了我們就具有nodeJS環境了
第二步,為了方便我們后面操作,我們直接在D盤見了一個文件夾blog
然后打開windows命令行工具,進入d盤,輸入:
express -e blog
然后里面可能有依賴包,我們需要進入blog目錄安裝(安裝的配置由package.json提供):
npm install
這個樣子,我們依賴包就下載下來了,其中依賴包與java的包文件,.net的bll文件應該是一個概念
這個時候,我們的程序已經可以運行了:
node app
D:\blog>node app
Express server listening on port 3000
這個時候打開瀏覽器就有反應了:
這里我們使用的是express(一個流行的nodeJSweb開發框架),並且使用了ejs模板引擎
文件結構
初始化文件目錄結構如下:
app.js 為入口文件
package.json 為模塊依賴文件,我們使用npm install時候他會以其配置在網上下載相關包
node_modules 為下載下來的模塊文件(package.json)
public 存放靜態資源文件
routes 存放路由文件
views 存放相關視圖模板文件
這個樣子,我們基本目錄結構就出來了,我們這里先簡單說下node_modules這個目錄
node_modules/ejs
我們剛剛說了,這里面存放着下載下來的模塊,說白了就是js文件集合

1 var parse = exports.parse = function(str, options){ 2 var options = options || {} 3 , open = options.open || exports.open || '<%' 4 , close = options.close || exports.close || '%>' 5 , filename = options.filename 6 , compileDebug = options.compileDebug !== false 7 , buf = ""; 8 9 buf += 'var buf = [];'; 10 if (false !== options._with) buf += '\nwith (locals || {}) { (function(){ '; 11 buf += '\n buf.push(\''; 12 13 var lineno = 1; 14 15 var consumeEOL = false; 16 for (var i = 0, len = str.length; i < len; ++i) { 17 var stri = str[i]; 18 if (str.slice(i, open.length + i) == open) { 19 i += open.length 20 21 var prefix, postfix, line = (compileDebug ? '__stack.lineno=' : '') + lineno; 22 switch (str[i]) { 23 case '=': 24 prefix = "', escape((" + line + ', '; 25 postfix = ")), '"; 26 ++i; 27 break; 28 case '-': 29 prefix = "', (" + line + ', '; 30 postfix = "), '"; 31 ++i; 32 break; 33 default: 34 prefix = "');" + line + ';'; 35 postfix = "; buf.push('"; 36 } 37 38 var end = str.indexOf(close, i) 39 , js = str.substring(i, end) 40 , start = i 41 , include = null 42 , n = 0; 43 44 if ('-' == js[js.length-1]){ 45 js = js.substring(0, js.length - 2); 46 consumeEOL = true; 47 } 48 49 if (0 == js.trim().indexOf('include')) { 50 var name = js.trim().slice(7).trim(); 51 if (!filename) throw new Error('filename option is required for includes'); 52 var path = resolveInclude(name, filename); 53 include = read(path, 'utf8'); 54 include = exports.parse(include, { filename: path, _with: false, open: open, close: close, compileDebug: compileDebug }); 55 buf += "' + (function(){" + include + "})() + '"; 56 js = ''; 57 } 58 59 while (~(n = js.indexOf("\n", n))) n++, lineno++; 60 if (js.substr(0, 1) == ':') js = filtered(js); 61 if (js) { 62 if (js.lastIndexOf('//') > js.lastIndexOf('\n')) js += '\n'; 63 buf += prefix; 64 buf += js; 65 buf += postfix; 66 } 67 i += end - start + close.length - 1; 68 69 } else if (stri == "\\") { 70 buf += "\\\\"; 71 } else if (stri == "'") { 72 buf += "\\'"; 73 } else if (stri == "\r") { 74 // ignore 75 } else if (stri == "\n") { 76 if (consumeEOL) { 77 consumeEOL = false; 78 } else { 79 buf += "\\n"; 80 lineno++; 81 } 82 } else { 83 buf += stri; 84 } 85 } 86 87 if (false !== options._with) buf += "'); })();\n} \nreturn buf.join('');"; 88 else buf += "');\nreturn buf.join('');"; 89 return buf; 90 };
就如,我們這里使用到的ejs模板以及express模塊,然后我們好奇的走進了ejs的程序看看究竟有何不同
打開,ejs.js后,我們抽一點代碼出來看:這段代碼我們比較熟悉,他與underscore的模板引擎代碼思想一致,都是將模板解析為字符串
然后通過eval或者new Function的方法將之轉換為函數,並且傳入自己的數據對象好解析
至於具體工作流程,現在我們還不知道,只能放到后面點研究了,好了我們現在進入其他模塊
app.js
作為入口文件,app.js扮演着舉足輕重的角色:
1 /** 2 * Module dependencies. 3 */ 4 5 var express = require('express'); 6 var routes = require('./routes'); 7 var user = require('./routes/user'); 8 var http = require('http'); 9 var path = require('path'); 10 11 var app = express(); 12 13 // all environments 14 app.set('port', process.env.PORT || 3000); 15 app.set('views', path.join(__dirname, 'views')); 16 app.set('view engine', 'ejs'); 17 app.use(express.favicon()); 18 app.use(express.logger('dev')); 19 app.use(express.json()); 20 app.use(express.urlencoded()); 21 app.use(express.methodOverride()); 22 app.use(app.router); 23 app.use(express.static(path.join(__dirname, 'public'))); 24 25 // development only 26 if ('development' == app.get('env')) { 27 app.use(express.errorHandler()); 28 } 29 30 app.get('/', routes.index); 31 app.get('/users', user.list); 32 33 http.createServer(app).listen(app.get('port'), function(){ 34 console.log('Express server listening on port ' + app.get('port')); 35 });
我們通過require()命令加載express、http模塊,並且會加載routes目錄下index user等模板文件
app.set('port', process.env.PORT || 3000)為設置啟動時候的端口
app.set('views', __dirname + '/views')為設置存放模板文件的路徑,其中__dirname為全局變量,存放當前腳本所在目錄,我們這樣可以查看:
console.log(__dirname);//index.js加入以下代碼 /** D:\blog>node app Express server li D:\blog\routes */
至於這個__dirname是如何獲得的,我們暫時也不需要關注
app.set('view engine', 'ejs') 為設置模板引擎為ejs
app.use(express.favicon()) 是設置圖標想修改的話就自己去搞public下面的images文件
app.use(express.logger('dev')); express依賴於connect這里就內建中間件會輸出一些日志
app.use(express.json()); 用以解析請求體,這里就會把字符串動態轉換為json對象
app.use(express.methodOverride()); connect內建中間件,用以處理post請求,並可以偽裝put等http方法
app.use(app.router); 調用路由器解析規則
app.use(express.static(path.join(__dirname, 'public'))); connect內建中間件,設置根目錄下的public存放靜態文件
if ('development' == app.get('env')) { app.use(express.errorHandler()); }
這句話意思是開發狀況下要輸出錯誤信息
app.get('/', routes.index);
app.get('/users', user.list);
這兩句都是訪問時刻具體的處理文件了,比如這里直接訪問時默認訪問的是routes.index
然后其內部才真正解析模板數據:
exports.index = function (req, res) { console.log(__dirname); res.render('index', { title: 'Express' }); };
http.createServer(app).listen(app.get('port'), function () { console.log('Express server listening on port ' + app.get('port')); });
最后會調用上述代碼創建http服務器並監聽3000端口,成功后便可在網頁上訪問了
路由
前面我們使用這個方法構建路由
app.get('/', routes.index);
上面代碼可以使用這個代碼取代(寫在app里面)
app.get('/', function (req, res) { res.render('index', { title: 'Express' }); });
這段代碼的意思是訪問主頁時,調用ejs模板引擎,來渲染index.ejs模板文件
現在再做一點修改,以上代碼實現了路由功能,但是我們不能將路由相關代碼放到app中,路由多了后app就會變得臃腫,所以我們將相關配置放入index中
所以刪除app中相關路由功能,在app結尾加入代碼:
routes(app);
然后修改index.js
module.exports = function(app) { app.get('/', function (req, res) { res.render('index', { title: 'Express' }); }); };
這個代碼是怎么組織的現在還不清楚,也不去關注了,我們后面慢慢看
路由規則
express封裝了多種http請求,我們一般使用get/post兩種
app.get();
app.post();
第一個參數為請求路徑,第二個參數為回調函數,還是兩個參數為request與response
然后,對於req(request)又有以下規則
req.query 處理get請求,獲取get請求參數
req.params 處理/:xxx形式的get或者post請求
req.body 處理post請求,獲取post請求體
req.params 處理get和post請求,但查找優先級為req.params->req.body->req.query
路徑規則還支持正則,具體我們以后再說......
添加路由規則
當我們訪問不存在的鏈接時:
因為不存在/y的路由規則,他也不說public下的文件,所以就404了
現在我們在index.js中添加相關路由:
module.exports = function (app) { app.get('/', function (req, res) { res.render('index', { title: 'Express' }); }); app.get('/y', function (req, res) { res.send('葉小釵'); }); };
這里我頁面亂碼了:
原因是下載下來后,我的文件是gbk的編碼,我們要將他改成utf-8就可以了,模板引擎這塊我們就不管他了,我們進入下一節
注冊功能
這里我們跟着原博主一起做一個注冊的簡單功能,這里使用mongo db作為數據庫,后面我們再依次完善功能
新建一個register路由,並且為其新建register模板,於是我們開始吧
① 在index中新建路由
app.get('/register', function (req, res) { res.render('index', { title: '注冊頁面' }); });
module.exports = function (app) { app.get('/', function (req, res) { res.render('index', { title: 'Express' }); }); app.get('/y', function (req, res) { res.send('葉小釵'); }); app.get('/register', function (req, res) { res.render('register', { title: '注冊頁面' }); });
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1><%= title %></h1> <form method="post"> <div>用戶名:<input type="text" name="name"/></div> <div>密碼:<input type="password" name="password"/></div> <div><input type="submit" value="登陸"/></div> </form> </body> </html>
這個樣子,我們頁面就形成了:
基本程序有了,我們現在需要數據庫支持,於是我們要安裝mongoDB環境
MongoDB
MongoDB是一個基於分布式文件存儲的NoSQL的一種,由C++編寫,MongoDB支持的數據結構松散,類似json,我們知道json可以支持任何類型,所以可以搞出很復雜的結構
{ id: 1, name: '葉小釵', frinds: [ { id: 2, name: '素還真' }, { id: 3, name: '一頁書' } ] }
安裝MongoDB
首先去http://www.mongodb.org/downloads下載安裝文件,然后將文件拷貝到D盤改名mongodb,然后在里面新建blog文件夾
然后打開命令行工具將目錄切換至bin,輸入:
mongod -dbpath d:\mongodb\blog
設置blog文件夾為工程目錄並啟動數據庫,為了方便以后我們寫一個命令以后直接點擊就啟動數據庫了:
d:\mongodb\bin\mongod.exe -dbpath d:\mongodb\blog
鏈接MongoDB
數據庫安裝成功后,我們的程序還需要相關的“驅動”程序才能鏈接數據庫,這個時候當然要下載包......
打開package.json在dependencies新加一行
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "express": "3.4.8", "ejs": "*", "mongodb": "*" } }
然后運行npm install下載新的依賴包,這個樣子與mongoDB相關的驅動就有了,要鏈接mysql等數據庫還需要其他依賴包
這時在根目錄下創建setting.js文件,保存數據庫連接信息
module.exports = { cookieSecret: 'myblog', db: 'blog', host: 'localhost' };
db是數據庫名稱,host是數據庫地址,cookieSecret用於cookie加密與數據庫無關
接下來根目錄下新建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, Connection.DEFAULT_PORT), {safe: true});
new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT), { safe: true });
設置數據庫名,數據庫地址和數據庫端口創建一個數據庫實例,並通過module.exports導出實例,這樣就可以通過require對數據庫進行讀寫
需要成功寫入數據庫,服務器端程序就需要處理post信息,於是我們在models文件夾下新建user.js
var mongodb = require('./db'); function User(user) { this.name = user.name; this.password = user.password; }; module.exports = User; //存儲用戶信息 User.prototype.save = function (callback) { //要存入數據庫的用戶文檔 var user = { name: this.name, password: this.password }; //打開數據庫 mongodb.open(function (err, db) { if (err) { return callback(err); //錯誤,返回 err 信息 } //讀取 users 集合 db.collection('users', function (err, collection) { if (err) { mongodb.close(); return callback(err); //錯誤,返回 err 信息 } //將用戶數據插入 users 集合 collection.insert(user, { safe: true }, function (err, user) { mongodb.close(); if (err) { return callback(err); //錯誤,返回 err 信息 } callback(null, user[0]); //成功!err 為 null,並返回存儲后的用戶文檔 }); }); }); };
//讀取用戶信息 User.get = function(name, callback) { //打開數據庫 mongodb.open(function (err, db) { if (err) { return callback(err);//錯誤,返回 err 信息 } //讀取 users 集合 db.collection('users', function (err, collection) { if (err) { mongodb.close(); return callback(err);//錯誤,返回 err 信息 } //查找用戶名(name鍵)值為 name 一個文檔 collection.findOne({ name: name }, function (err, user) { mongodb.close(); if (err) { return callback(err);//失敗!返回 err 信息 } callback(null, user);//成功!返回查詢的用戶信息 }); }); }); };
這里一個寫數據,一個讀數據,處理程序有了,現在需要在index.js前面加上如下程序
var User = require('../models/user.js');
再修改其中的app.post('/register')
app.post('/register', function (req, res) { var name = req.body.name; var pwd = req.body.password; var newUser = new User({ name: name, password: pwd }); newUser.save(function (err, user) { //相關操作,寫入session res.send(user); }); });
然后點擊注冊后便會有反應了
如果此時不能確定是否寫入數據庫,便可進入數據庫查詢一番,首先切換至數據庫目錄
D:\mongodb\bin>
輸入:
mongo
然后切換其數據庫連接至blog
use blog
最后輸入
db.users.find()
我們大家就開心的看到數據寫入了,於是今天的學習暫時告一段落
結語
今天我們跟着一篇博客完成了從安裝到寫入數據庫的操作,明天讓我們來將其它方面加入,逐步深化nodeJS的學習