原文: http://cwbuecheler.com/web/tutorials/2013/node-express-mongo/
太多的教程教你些一個Hello, World!了, 但是僅憑Hello, World! 是找不到工作的, 因此有了這篇教程.
PART I – 安裝開發環境
作者是在Windows 8上開發的.
STEP 1 – 安裝NODE.JS
打開 Node.js website 點擊綠色的安裝按鈕. 運行安裝程序就安裝好了, 就是這么簡單. 現在你已經安裝好Node.js了, 同樣NPM(Node Package Manager)也安裝好了
- 打開命令終端 cmd
- cd到你想要建立應用的目錄
(本教程是 C:\node).
STEP 2 – 安裝EXPRESS
現在我們安裝Express, Express是一個框架他能讓我們更簡單的建立一個web應用. 在命令終端運行:
C:\node>npm install -g express
(-g代表安裝到全局, 我感覺express不應該安裝到全局)
好消息: 你可以安裝一個express的"generator". 他能幫我們生成一個網站基本的框架, 讓我們少些了好多的代碼(如果你想了解更多可以去Yeoman 看看). 安裝generator也很容易, 在命令終端運行:
C:\node>npm install -g express-generator
好了是時候生成一個網站的基本框架了
STEP 3 – CREATE AN EXPRESS PROJECT
我們使用Express 和 Jade, 在命令終端輸入:
C:\node>express nodetest1
點擊回車, 你可以看到下面的東西
C:\node>express nodetest1 create : nodetest1 create : nodetest1/package.json create : nodetest1/app.js create : nodetest1/public create : nodetest1/public/javascripts create : nodetest1/public/images create : nodetest1/routes create : nodetest1/routes/index.js create : nodetest1/routes/users.js create : nodetest1/public/stylesheets create : nodetest1/public/stylesheets/style.css create : nodetest1/views create : nodetest1/views/index.jade create : nodetest1/views/layout.jade create : nodetest1/views/error.jade create : nodetest1/bin create : nodetest1/bin/www install dependencies: $ cd nodetest1 && npm install run the app: $ DEBUG=my-application ./bin/www
STEP 4 – 編輯依賴
現在我們的網站已經有一個基本的結構了, 但是我們現在還有一些事沒做. 你能注意到nodetest1目錄有一個叫package.json的文件. 文件的內容如下:
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "express": "~4.0.0", "serve-favicon": "~2.1.3", "morgan": "~1.0.0", "cookie-parser": "~1.0.1", "body-parser": "~1.0.0", "debug": "~0.7.4", "jade": "~1.3.0" } }
這些json內容描述了我們的網站和他的一些依賴. 我們需要添加一些東西. 現在讓我們在依賴里面添加MongoDB和Monk.
"dependencies": { "express": "~4.0.0", "serve-favicon": "~2.1.3", "morgan": "~1.0.0", "cookie-parser": "~1.0.1", "body-parser": "~1.0.0", "debug": "~0.7.4", "jade": "~1.3.0", "mongodb": "*", "monk": "*" }
STEP 5 – 安裝依賴
現在我們已經定義了我們的依賴. 注意星號代表獲取最新的版本. 打開終端 cd到nodetest1目錄, 輸入:
C:\node\nodetest1>npm install
現在終端會輸出一大堆的東西. 因為讀取JSON文件安裝我們定義的依賴對象. 運行完后, 你可以發現一個node_modules目錄, 里面包含了我們之前定義的依賴.
現在你的網站基本可以運行了. 在運行前我們需要設置一個數據庫目錄. 在終端輸入:
C:\node\nodetest1>mkdir data
這個目錄用來存儲我們的MongoDB數據. 如果這個目錄不存在的話, 數據庫會阻塞我們的網站. 好了現在我們可以來運行看看我們的網站了. 在終端輸入:
C:\node\nodetest1>npm start
回車后, 你可以在終端看到下面的東西
> application-name@0.0.1 start D:\sites\node\nodetest1 > node ./bin/www
打開瀏覽器, 輸入http://localhost:3000 你可以看到一個Express的歡迎頁面
PART 2 – 好了讓我們做個"HELLO, WORLD!"
用IDE打開app.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');
上面的代碼給package、依賴、node functionality和路由創建了相應的變量. 路由是modles和controllers的一種關聯. 這里我們忽略不去管user路由只關注於頂級路由 (c:\node\nodetest1\routes\index.js).
app.js
var app = express();
這個非常重要. 他實例化了一個Express並且分配給了app變量. 下面的代碼片段使用這個變量配置一堆express的東西.
app.js
// view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(__dirname + '/public/favicon.ico')); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes); app.use('/users', users);
上面的代碼告訴app去哪查找views(視圖), 使用何種視圖引擎展現我們的視圖(Jade), 另外調用了一些方法. 倒數第三行代碼告訴Express靜態文件放在public目錄, 我們獲取這些靜態文件的時候不需要在url中輸入public . 比如, 圖片目錄在c:\node\nodetest1\public\images, 但是我們通過http://localhost:3000/images 來進入到圖片目錄.
app.js
/// catch 404 and forwarding to error handler 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 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 app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); });
這里有兩種錯誤處理器, 一個是給開發環境用的,另一個是給生產環境使用的.
app.js
module.exports = app;
Node的一個核心部分就是module.exports. 我們的主app導出app對象.
我們先看看app.js現有的路由:
app.use('/', routes); app.use('/users', users);
上面的代碼告訴Express使用那些路由文件. 一般我提倡為應用的不同部分寫對應的路由文件. 例如, users路由文件可能包含添加用戶、刪除用戶、更新用戶的路由,locations路由文件處理添加、刪除、編輯、展示location的路由. 在我們的這個教程中, 為了簡單的演示, 我們只關注index路由.
Express generator已經定義了一個"routes" 變量指向index路由. 我們在index路由中添加"helloworld"方法展示一個新的頁面. 打開index.js:
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res) { res.render('index', { title: 'Express' }); }); module.exports = router;
在最后一行前加入下面的代碼:
/* GET Hello World page. */ router.get('/helloworld', function(req, res) { res.render('helloworld', { title: 'Hello, World!' }) });
現在我們還沒創建一個helloworld頁面. 打開views文件夾, 打開index.jade. 創建一個helloworld.jade文件內容拷貝index.jade的內容.
現在helloworld.jade的內容如下:
extends layout block content h1= title p Welcome to #{title}
使用("extends") 將layout.jade作為一個模板, 接下來在layout文件定義的content block下面輸出一個h1和p標簽. 注意"title"參數是我們在index.js路由中已經定義了的.
下面讓我們改變p的內容:
p Hello, World! Welcome to #{title}
保存文件,回到終端, 按ctrl-c退出服務, 輸入:
npm start
順便說一下, 修改Jade模板不需要重啟服務, 但是修改app.js或者路由這樣的.js文件需要重啟服務.
現在打開http://localhost:3000/helloworld 頁面, 效果如下:
PART 3 – 創建數據庫
STEP 1 – 安裝MONGODB
打開http://mongodb.org/ 下載Mongo. 你會得到一個zip文件, 解壓到一個臨時的目錄. 創建一個目錄放Mongo, 把解壓后的文件放到這個新的目錄下.
STEP 2 – 運行MONGOD和MONGO
在你的nodetest1目錄, 新建一個data子目錄. 先cd到你安裝mongo的目錄, 然后輸入:
mongod --dbpath c:\node\nodetest1\data
Mongo服務運行了. 第一次會消耗一定的時間, 因為mongo要預先分配一些空間, 另外還要運行一些任務. 當看到終端輸出"[initandlisten] waiting for connections on port 27017", 這代表啟動完成了. 現在另開一個終端cd到mongo的安裝目錄, 輸入:
mongo
回車后看到下面的內容
c:\mongo>mongo MongoDB shell version: 2.4.5 connecting to: test
這告訴你連接已經建立好了
STEP 3 – 創建數據庫
"connecting to: test" …test是mongo默認使用的數據庫. 其實這個時候還沒有真正的創建了一個名為test的數據庫, 除非你給test創建了一條記錄, 這個時候test數據庫才真正的被創建. 在Mongo console 中輸入:
use nodetest1
現在我們使用"nodetest1數據庫, 和上面講到的"test"一樣, 這個時候我們並沒有真正的創建了nodetest1數據庫. 為了真正的創建這個數據庫, 我們應該添加一些數據.
STEP 4 – 添加數據
添加一些數據到我們的collection. 在這個教程中, 我們的數據比較簡單, 只需要一個username和email.數據格式如下:
{ "_id" : 1234, "username" : "cwbuecheler", "email" : "cwbuecheler@nospam.com" }
在mongo終端輸入:
db.usercollection.insert({ "username" : "testuser1", "email" : "testuser1@testdomain.com" })
這里要注意的是: "db" 代表我們的數據庫, 這里是我們上面定義的"nodetest1"."usercollection" 是我們的collection. 注意我們沒有一個創建usercollection的步驟. 因為第一次使用的時候他會自動被創建.回車. 如果一切順利的話, 終端不會輸出任何東西. 現在輸入:
db.usercollection.find().pretty()
.pretty() 方法會使得輸出自動換行, 這樣返回的內容的可讀性更好. 返回內容如下:
{ "_id" : ObjectId("5202b481d2184d390cbf6eca"), "username" : "testuser1", "email" : "testuser1@testdomain.com" }
現在我們一次插入多條記錄
newstuff = [{ "username" : "testuser2", "email" : "testuser2@testdomain.com" }, { "username" : "testuser3", "email" : "testuser3@testdomain.com" }] db.usercollection.insert(newstuff);
是的, 我們可以傳遞一個對象數組給我們的collection
STEP 5 – HOOK MONGO UP TO NODE
讓我們開始創建一個頁面顯示數據路里面的內容. 這里是我們期望的得到的html
<ul> <li><a href="mailto:testuser1@testdomain.com">testuser1</a></li> <li><a href="mailto:testuser2@testdomain.com">testuser2</a></li> <li><a href="mailto:testuser3@testdomain.com">testuser3</a></li> </ul>
我們需要在app.js文件中添加幾行代碼, 用來連接我們的MongoDB. 打開app.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');
現在讓我們來添加3行代碼
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'); // New Code var mongo = require('mongodb'); var monk = require('monk'); var db = monk('localhost:27017/nodetest1');
這幾行代碼告訴我們的應用我們想使用MongoDB, 這里使用的是Monk(現在Mongoose比較流行), 我們的數據庫位於localhost:27017/nodetest1. 注意27017是MOngoDB的默認端口. 現在看到app.js文件的底部, 代碼如下:
app.use('/', routes); app.use('/users', users);
在這我們需要做點工作.app.use語句是為Express建立中間件. 簡短的說: 他們提交了一些自定義的函數使得你的app更加有用. 他們很簡單, 但是要注意的是他們必須放在路由定義前才能生效.
在上面兩行代碼前加入下面的代碼
// Make our db accessible to our router app.use(function(req,res,next){ req.db = db; next(); });
注意: 如果你不是將上面的代碼放在 app.use('/', routes) 之上, 你新加的代碼就不會起作用.
當我們添加Mongo和Monk到app.js的時候我們已經定義了db. db是我們的Monk連接對象. 在把上面的代碼添加到app.use后, 每個HTTP request對象都有一個db了. 注意: 這個對性能來說可能不是最好的選擇, 但是我們這里是講快速搭建.
再次強調, 上面的代碼必須放在我們的路由之上. 現在你的app.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'); // New Code var mongo = require('mongodb'); var monk = require('monk'); var db = monk('localhost:27017/nodetest1'); var routes = require('./routes/index'); var users = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(__dirname + '/public/favicon.ico')); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // Make our db accessible to our router app.use(function(req,res,next){ req.db = db; next(); }); app.use('/', routes); app.use('/users', users); /// catch 404 and forwarding to error handler 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 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 app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app;
接下來我們要修改我們的路由, 這樣我們就能使用數據庫來展現數據了.
STEP 6 – PULL YOUR DATA FROM MONGO AND DISPLAY IT
在編輯器中打開 C:\node\nodetest1\routes\index.js. 現在讓我們來添加一個路由:
/* GET Userlist page. */ router.get('/userlist', function(req, res) { var db = req.db; var collection = db.get('usercollection'); collection.find({},{},function(e,docs){ res.render('userlist', { "userlist" : docs }); }); });
下一步我們要設置我們的Jade 模版. 導航到C:\node\nodetest1\views\打開index.jade文件. 復制其內容到新建的userlist.jade, 編輯內容如下:
extends layout block content h1. User List ul each user, i in userlist li a(href="mailto:#{user.email}")= user.username
each中的user代表迭代中的user, i(index)是一個計數器.
保存文件, 重啟node服務:
C:\node\nodetest1>npm start
Now open your browser and head to http://localhost:3000/userlist and marvel in the results.
現在你從數據庫里面取出來數據展現在網頁上了!
PART 4 – 數據庫的寫操作
數據庫的寫操作不難. 記住寫操作一般用 HTTP POST
STEP 1 – 創建數據輸入框CREATE YOUR DATA INPUT
我們先為添加用戶的表單頁面添加一個路由. 打開/routes/index.js 添加下面的代碼(在module.exports前) :
/* GET New User page. */ router.get('/newuser', function(req, res) { res.render('newuser', { title: 'Add New User' }); });
現在我們添加一個jade模版頁面 newuser.jade:
extends layout block content h1= title form#formAddUser(name="adduser",method="post",action="/adduser") input#inputUserName(type="text", placeholder="username", name="username") input#inputUserEmail(type="text", placeholder="useremail", name="useremail") button#btnSubmit(type="submit") submit
重啟node服務, 打開 http://localhost:3000/newuser 內容如下:
現在點擊submit按鈕會得到一個404錯誤.
STEP 2 – 創建我們的數據功能
現在我們要做的是添加一個Post路由名為 /adduser.
打開 /routes/index.js 添加下面的內容:
/* POST to Add User Service */ router.post('/adduser', function(req, res) { // Set our internal DB variable var db = req.db; // Get our form values. These rely on the "name" attributes var userName = req.body.username; var userEmail = req.body.useremail; // Set our collection var collection = db.get('usercollection'); // Submit to the DB collection.insert({ "username" : userName, "email" : userEmail }, function (err, doc) { if (err) { // If it failed, return error res.send("There was a problem adding the information to the database."); } else { // If it worked, set the header so the address bar doesn't still say /adduser res.location("userlist"); // And forward to success page res.redirect("userlist"); } }); });
STEP 3 – 連結並且添加一些數據到數據庫
確定mongod是正在運行的! 下面重啟node :
C:\node\nodetest1>npm start
現在我們打開 http://localhost:3000/newuser 添加一些內容(下面的網址不正確請忽略網址).
點擊submit, 我們會跳轉到 /userlist 頁面, 在這個頁面中可以看到我們添加的新用戶!