最近心血來潮又把 express 玩了一下,寫篇文章來紀錄一下整個過程,會用到的工具如下:
- express 4
- node-orm2
- nodemon
首先安裝 express-generator,這是一個可以自動產生 express 需要內容的工具
$ sudo npm i -g express-generator
安裝好之後,我們切換到我們想要的目錄來產生專案資料夾,我選用 twig 當作我的樣板引擎,我在 PHP 使用 CI 的時候也是選用同一個引擎,可以無痛轉移
| /var/www $ sudo express -v twig project |
| |
| /var/www $ cd project |
| /var/www/project $ sudo npm i |
| /var/www/project $ sudo npm i orm mysql --save |
專案目錄產生後,我們可以使用 nodemon 來監控目錄,也可以達到修改檔案後自動重起的效果
/var/www/project $ sudo nodemon bin/www
這時候打開 http://10.10.10.16:3000
(我的 vm 測試 IP)就可以看到預設網址,如果希望改 port 的話可以在 env 設定 port,或者直接去改 bin/www
這個檔案
打開 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 index = require('./routes/index'); |
| var users = require('./routes/users'); |
| |
| var app = express(); |
| |
| |
| app.set('views', path.join(__dirname, 'views')); |
| app.set('view engine', 'twig'); |
| |
| |
| |
| app.use(logger('dev')); |
| app.use(bodyParser.json()); |
| app.use(bodyParser.urlencoded({ extended: false })); |
| app.use(cookieParser()); |
| app.use(express.static(path.join(__dirname, 'public'))); |
| |
| app.use('/', index); |
| app.use('/users', users); |
| |
| |
| app.use(function(req, res, next) { |
| var err = new Error('Not Found'); |
| err.status = 404; |
| next(err); |
| }); |
| |
| |
| app.use(function(err, req, res, next) { |
| |
| res.locals.message = err.message; |
| res.locals.error = req.app.get('env') === 'development' ? err : {}; |
| |
| |
| res.status(err.status || 500); |
| res.render('error'); |
| }); |
| |
| module.exports = app; |
所有的動作都在這隻 app.js 設定,我們來建立一個 product routes 檔案
routes/product.js
| const express = require('express'); |
| const router = express.Router(); |
| |
| router.get('/', function(req, res, next) { |
| res.render('product/index'); |
| }); |
| |
| module.exports = router; |
view/product/index.twig
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title></title> |
| </head> |
| <body> |
| <h3>This is product page</h3> |
| </body> |
| </html> |
將 app.js
加上這個 routes 的設定
app.js
| var index = require('./routes/index'); |
| var users = require('./routes/users'); |
| var product = require('./routes/product'); |
| var index = require('./routes/index'); |
| var users = require('./routes/users'); |
| var product = require('./routes/product'); |
| |
| app.use('/', index); |
| app.use('/users', users); |
| app.use('/product', product); |
這時網址改成 http://10.10.10.16:3000/product
,就會看到 This is product page 這幾個字
接下來我們進行資料庫的串連,在 MySQL 內建立一個叫 express
的資料庫,另外建立一個 products
的 table 並且塞入資料
| CREATE TABLE `products` ( |
| `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, |
| `name` VARCHAR(50) NOT NULL |
| ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci; |
接下來我們來設定資料庫連接,因為我不喜歡全部的東西都塞在 app.js
,所以我另外開一個資料夾來放設置檔
config/db.js
| module.exports = (app, orm) => { |
| app.use(orm.express("mysql://root:123456@127.0.0.1/express", { |
| define: function(db, models, next) { |
| models.product = db.define('products', { |
| id: Number, |
| name: String |
| }); |
| next(); |
| } |
| })); |
| }; |
修改 app.js 啟動這個設定,只要放在 app
以及 orm
初始化後即可
app.js
require('./config/db.js')(app, orm);
我們先將 routes/product.js
修改成以下內容,變可以從網址先看到結果
| const express = require('express'); |
| const router = express.Router(); |
| |
| router.get('/', function(req, res, next) { |
| req.models.product.all((err, data) => { |
| res.json(data); |
| }) |
| }); |
| |
| module.exports = router; |
[{"id":1,"name":"product a"},{"id":2,"name":"product b"}]
這是最基本的用法,但我覺得這樣可重複利用性太低了,所以我們來建立類似 model 機制吧
routes/product.js
| const express = require('express'); |
| const router = express.Router(); |
| const Product = require('../model/product.js'); |
| |
| router.get('/', async(req, res, next) => { |
| try { |
| const product = new Product(req.models.product); |
| res.json(await product.getAllNews()); |
| } catch (e) { |
| res.send(e); |
| } |
| }); |
| |
| module.exports = router; |
model/product.js
| class Product { |
| constructor(model) { |
| this.model = model |
| } |
| |
| async getAllNews() { |
| return new Promise((resolve, reject) => { |
| this.model.all((err, data) => { |
| if (err) { |
| reject(err); |
| } |
| |
| resolve(data); |
| }) |
| }) |
| } |
| } |
| |
| module.exports = Product; |
這樣的執行結果會一模一樣,但把東西拆乾淨模組化了,再修改一次在 view 呈現吧
routes/product.js
| const express = require('express'); |
| const router = express.Router(); |
| const Product = require('../model/product.js'); |
| |
| router.get('/', async(req, res, next) => { |
| try { |
| const product = new Product(req.models.product); |
| res.render('product/index', { |
| products: await product.getAllNews() |
| }); |
| } catch (e) { |
| res.send(e); |
| } |
| }); |
| |
| module.exports = router; |
views/product/index.twig
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title></title> |
| </head> |
| <body> |
| <h3>This is product page</h3> |
| {% for product in products %} |
| <div>product: {{ product.name }}</div> |
| {% endfor %} |
| </body> |
| </html> |
以上就是這兩天試玩 express
的整理,沒有實現所謂的 controller 部份,就先把 routes 當 controller,當然一定會有更多更好的方法,再慢慢探索,在此也感謝陳默司大大的指導