這一系列文章為 [BE201] 後端 Express 學習筆記,主要紀錄學習過程,裡面包含 express 基本原理、基本操作、Middleware 介紹,最後以留言板來練習 express 實作
零、內容摘要
介紹如何不用框架實作一個 server,藉此了解基本原理
Express 建立基本環境,並理解用 Express 跟之前第九週用 Apache + PHP 的差別
Express 基本架構
一、要學框架,從不用框架先開始
server 只是一個程式,在介紹 Express 框架以前,先來看一下如何不用框架,實作底層的 server
用 node.js 實作一個 server
const http = require('http')
const server = http.createServer(handler)
function handler(req, res) {
console.log(req.url)
res.write('hello!')
res.end()
}
server.listen(5001)
一個簡單導向的概念
const http = require('http')
const server = http.createServer(handler)
function handler(req, res) {
console.log(req.url)
if (req.url === '/hello') {
res.write('hello!')
} else if (req.url ==='/bye'){
res.write('bye!')
} else {
res.write('invalid url')
}
res.end()
}
server.listen(5001)
二、初探 Express
如何建立一個 Express 環境
a. $ npm init
,接著全按 enter
b. $ npm install express
c. 開新檔案,參考文件 Hello world example 引入 library
註:在 dev tool 記得要把 cache 打勾
const express = require('express')
const app = express()
const port = 5001
app.get('/', (req, res) => {
res.send('hello')
})
app.get('/hello', (req, res) => {
res.send('hello, man')
})
app.get('/bye', (req, res) => {
res.send('bye, man')
})
app.listen(port, () => {
console.log('success')
})
三、與之前 Apache + PHP 組合的差別在哪?
- Apache + PHP: 瀏覽器 -> Apache server -> PHP,處理完再 PHP -> Apache server -> 瀏覽器
Apache + PHP檔案結構長怎樣,url 就長怎樣
- Express: 瀏覽器 -> Express server
四、Express 基本架構
1. 基礎介紹
在 node.js 嘗試 MVC 架構,這裡用一個叫 EJS 的 template ,跟 PHP 蠻像的、蠻簡單的一個 template。
用 template 感覺就是把資料塞進去一個模板裡面,EJS,通常用 <% %>
操作
參考文件:Using template engines with Express
開始安裝:
a. $ npm install ejs
b. set engine to ejs app.set('view engine', 'ejs')
c. create a new folder named views and inside a new file named hello.ejs
d. 路徑說明
// 如果路徑是 '/hello',就去 render 叫做 hello 的檔案
app.get('/hello', (req, res) => {
res.render('hello')
})
hello 檔案裡面的更動只要重新整理就會顯示,不需要重開 node
2. 先來個畫面吧,實作一個只能看的 todolist
todo list 畫面,對應網址:http://localhost:5001/todos
todos
- first todo
- second todo
- third todo
// index.js
const express = require('express')
const app = express()
const port = 5001
app.set('view engine', 'ejs')
const todos = [
'first todo', 'second todo', 'third todo'
]
app.get('/todos', (req, res) => {
res.render('todos', {
todos
})
})
app.listen(port, () => {
console.log('success')
})
// todos.ejs
<h1>todos</h1>
<ul>
<% for(let i=0; i<todos.length; i++) { %>
<li><%= todos[i] %></li> // 用 = 來輸出
<% } %>
</ul>
單個 todo 畫面,對應網址:http://localhost:5001/todos/0
todo
first todo
// todo.ejs
<h1>todo</h1>
<h2><%= todo %></h2>
// index.js
app.get('/todos/:id', (req, res) => {
const id = req.params.id
const todo = todos[id]
res.render('todo', {
todo
})
})
3. 把架構切成 MVC
運作方式:
model 資料
view 顯示畫面
controller 去 model 拿資料並且把資料給 view 顯示
資料夾結構:
controllers folder
- todo.js 去 model 拿資料並把資料給畫面顯示
models folder
- todo.js 有 getAll & get 兩個 methods
views folder
todo.ejs 顯示單個 todo
todos.ejs 顯示整個 todos
index.js
// controllers > todo.js
const todoModel = require('../models/todo')
const todoController = {
getAll: (req, res) => {
const todos = todoModel.getAll()
res.render('todos', {
todos
})
},
get: (req, res) => {
const id = req.params.id
const todo = todoModel.get(id)
res.render('todo', {
todo
})
}
}
module.exports = todoController
// models > todo.js
const todos = [
'first todo', 'second todo', 'third todo'
]
const todoModel = {
getAll: () => {
return todos
},
get: (id) => {
return todos[id]
}
}
module.exports = todoModel
// views > todo.ejs
<h1>todo</h1>
<h2><%= todo %></h2>
// views > todos.ejs
<h1>todos</h1>
<ul>
<% for(let i=0; i<todos.length; i++) { %>
<li><%= todos[i] %></li>
<% } %>
</ul>
// index.js
const express = require('express')
const app = express()
const port = 5001
const todoController = require('./controllers/todo')
app.set('view engine', 'ejs')
app.get('/todos', todoController.getAll)
app.get('/todos/:id', todoController.get)
app.listen(port, () => {
console.log('success')
})
五、Node.js 與 MySQL 的串接
1. 影片裡用的是 sequel pro 來操作 MySQL
Sequel Pro 語言介面恢復英文、如何用 sequel pro 連到之前 xampp 的資料庫
error log:
裝好 Sequel Pro 以後無法登入,試了以前的所有帳密的組合都登不進去
後來又下載了 MySQL 然後不知道自己在幹嘛
經過一番回想,終於想起導讀有提示,花了幾個小時在上面,嗚嗚。
2. 開始安裝
參考文件:mysql
a. $ npm install mysql
b. 開資料庫
c. 新增 db.js 檔案(在參考文件的 introduction 裡面)
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'your name',
password : '*****',
database : 'todos'
});
connection.connect();
connection.query('SELECT * from todos', function (error, results, fields) {
if (error) throw error;
console.log(results);
});
connection.end();
這樣寫其他地方比較好用
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'your name',
password : '*****',
database : 'todos'
});
module.exports = connection
d. $ node db.js
,成功得到資料了!
[
RowDataPacket { id: 1, content: 'todo1\n' },
RowDataPacket { id: 2, content: 'todo2\n' },
RowDataPacket { id: 3, content: 'todo3\n' }
]
e. 連線 db
// index.js
const db = require('./db')
app.listen(port, () => {
db.connect()
console.log('success')
})
f. 改 model
// todos.js
const db = require('../db')
const todoModel = {
getAll: (cb) => {
db.query(
'SELECT * from todos', (err, results) => {
if (err) return cb(err)
cb(null, results)
});
},
// 在文件裡搜尋「prepared statements」 防止 sql injection
get: (id, cb) => {
db.query(
'SELECT * from todos where id = ?', [id], (err, results) => {
if (err) return cb(err)
cb(null, results)
});
}
}
module.exports = todoModel
g. 改 controller
const todoModel = require('../models/todo')
const todoController = {
getAll: (req, res) => {
todoModel.getAll((err, results) => {
if (err) return console.log(err)
res.render('todos', {
todos: results
})
})
},
get: (req, res) => {
const id = req.params.id
todoModel.get(id, (err, results) => {
if (err) return console.log(err)
res.render('todo', {
todo: results[0]
})
})
}
}
module.exports = todoController
h. views 也要改
// todos.ejs
<h1>todos</h1>
<ul>
<% for(let i=0; i<todos.length; i++) { %>
<li><%= todos[i].id + ': ' + todos[i].content %></li>
<% } %>
</ul>
// todo.ejs
<h1>todo</h1>
<h2><%= todo.content %></h2>