實作簡易留言板
index.js
主要新增內容
app.get('/', commentController.index)
- 要先取得留言內容,再 render 首頁,
app.post('/comment', commentController.add)
- 加一個新增留言的路由
程式碼
const express = require('express')
const bodyParser = require('body-parser')
const session = require('express-session')
const flash = require('connect-flash')
const db = require('./db')
const app = express()
const port = 5001
const todoController = require('./controllers/todo'
)
const userController = require('./controllers/user')
const commentController = require('./controllers/comment')
app.set('view engine', 'ejs')
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(flash())
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
}))
app.use((req, res, next) => {
res.locals.username = req.session.username
res.locals.errorMessage = req.flash('errorMessage')
next()
})
function redirectBack(req, res) { // 自己寫的 Middleware
res.redirect('back')
}
app.post('/todos', todoController.newTodo)
app.get('/todos', todoController.getAll)
app.get('/todos/:id', todoController.get)
app.get('/', commentController.index)
app.get('/login', (req, res) => {
res.render('login')
})
app.get('/login', userController.login)
app.post('/login', userController.handleLogin, redirectBack)
app.get('/logout', userController.logout)
app.get('/register', userController.register)
app.post('/register', userController.handleRegister, redirectBack)
app.post('/comment', commentController.add)
app.post('/login', (req, res) => {
if (req.body.password === "abc") {
req.session.isLogin = true
res.redirect('/')
} else {
req.flash('errorMessage', 'Please input the correct password')
res.redirect('/login')
}
})
app.get('/logout', (req, res) => {
req.session.isLogin = false
res.redirect('/')
})
app.listen(port, () => {
db.connect()
console.log(`hello world, listening on port ${port}`)
})
controller
comment.js 程式碼
const commentModel = require('../models/comment')
const commentController = {
add: (req, res) => {
const {username} = req.session
const {content} = req.body
if (!username || !content) {
return res.redirect('/')
}
commentModel.add(username, content, (err) => {
return res.redirect('/')
})
},
index: (req, res) => {
commentModel.getAll((err, results) => {
if (err) {
console.log(err)
}
res.render('user/index', { // 送一個參數到 index.ejs,這樣它就可以拿到所有評論
comments: results
})
})
}
}
module.exports = commentController
models
comment.js 的程式碼
const db = require('../db')
const commentModel = {
add: (username, content, cb) => { // 傳進 user 這個 Object
db.query(
'INSERT INTO yide_comments (username, content) VALUES (?, ?)',
[username, content],
(error, results) => {
if (error) return cb(error);
cb(null)
});
},
getAll: (cb) => {
db.query(
`SELECT U.nickname, C.content
FROM yide_comments as C
LEFT JOIN yide_users as U on U.username = C.username
ORDER BY C.id DESC`,
(error, results) => {
if (error) return cb(error);
cb(null, results)
});
}
}
module.exports = commentModel
view
index.ejs 程式碼
<h1>簡易會員系統</h1>
<!--先判斷是否有登入-->
<% if (username) { %>
Hello, <%= username %>
<a href='/logout'>登出</a>
<form method="POST" action="/comment" >
<textarea name="content"></textarea>
<input type="submit" />
</form>
<% } else { %>
<a href='/register'>註冊</a>
<a href='/login'>登入</a>
<% } %>
<% comments.forEach(function(comment) { %>
<div>
<h2><%= comment.nickname %></h2>
<p><%= comment.content %></p>
</div>
<% }) %>
實作刪除、編輯功能
index.js
新增程式碼
pp.get('/delete_comment/:id', commentController.delete) // 冒號 id 代表它是一個動態參數
app.get('/update_comment/:id', commentController.update)
app.post('/update_comment/:id', commentController.handleUpdate)
controller
comment.js 程式碼
const commentModel = require('../models/comment')
const commentController = {
add: (req, res) => {
const {username} = req.session
const {content} = req.body
if (!username || !content) {
return res.redirect('/')
}
commentModel.add(username, content, (err) => {
return res.redirect('/')
})
},
index: (req, res) => {
commentModel.getAll((err, results) => {
if (err) {
console.log(err)
}
res.render('user/index', { // 送一個參數到 index.ejs,這樣它就可以拿到所有評論
comments: results
})
})
},
delete: (req, res) => {
commentModel.delete(req.session.username, req.params.id, (err) => { // 權限檢查、把 id 傳下去
res.redirect('/')
})
},
update: (req, res) => {
commentModel.get(req.params.id, (err, results) => {
res.render('update', {
comment: results
})
})
},
handleUpdate: (req, res) => {
commentModel.update(req.session.username, req.params.id, req.body.content, (err) => {
res.redirect('/')
}) // 做權限管理
}
}
module.exports = commentController
models
comment.js
const db = require('../db')
const commentModel = {
add: (username, content, cb) => { // 傳進 user 這個 Object
db.query(
'INSERT INTO yide_comments (username, content) VALUES (?, ?)',
[username, content],
(error, results) => {
if (error) return cb(error);
cb(null)
});
},
getAll: (cb) => {
db.query(
`SELECT U.nickname, C.content, C.id, C.username
FROM yide_comments as C
LEFT JOIN yide_users as U on U.username = C.username
ORDER BY C.id DESC`,
(error, results) => {
if (error) return cb(error);
cb(null, results)
});
},
delete: (username, id, cb) => {
db.query(
`DELETE FROM yide_comments WHERE id = ? AND username = ?`,
[id, username],
(error, results) => {
if (error) return cb(error);
cb(null, results)
});
},
get: (id, cb) => {
db.query(
`SELECT U.nickname, C.content, C.id, C.username
FROM yide_comments as C
LEFT JOIN yide_users as U on U.username = C.username
WHERE C.id = ?`,
[id],
(error, results) => {
if (error) return cb(error);
cb(null, results[0] || {}) // 傳一個空的 object 進去,這樣如果沒有 results 就不會壞掉
});
},
update: (username, id, content, cb) => {
db.query(
`UPDATE yide_comments SET content = ? WHERE username = ? AND id = ?`, // 檢查 username 作權限管理
[content, username, id],
(error, results) => {
if (error) return cb(error);
cb(null, results)
});
},
}
module.exports = commentModel
view
index.ejs
<h1>簡易會員系統</h1>
<!--先判斷是否有登入-->
<% if (username) { %>
Hello, <%= username %>
<a href='/logout'>登出</a>
<form method="POST" action="/comment" >
<textarea name="content"></textarea>
<input type="submit" />
</form>
<% } else { %>
<a href='/register'>註冊</a>
<a href='/login'>登入</a>
<% } %>
<% comments.forEach(function(comment) { %>
<div>
<h2><%= comment.nickname %></h2>
<p><%= comment.content %></p>
<% if (username === comment.username) { %>
<a href="/update_comment/<%= comment.id %>">編輯</a>
<a href="/delete_comment/<%= comment.id %>">刪除</a>
<% } %>
</div>
<% }) %>
update.ejs
<h1>編輯文章</h1>
<form method="POST" action="/update_comment/<%= comment.id %>" >
<textarea name="content"><%= comment.content %></textarea>
<input type="submit" />
</form>
美化頁面
在 view 裡面新增 template 這個資料夾,裡面可以放 navbar、header、footer⋯⋯等的模板,再利用 <%- include(<路徑>) %>
的方式引入進來
範例:index.ejs 的程式碼
<!doctype html>
<head>
<%- include('../template/head') %>
</head>
<html>
<%- include('../template/navbar') %>
<div class="container">
<% if (username) { %>
<form method="POST" action="/comment" >
<div class="form-group">
<label>留言內容</label>
<textarea name="content" class="form-control" ></textarea>
</div>
<button type="submit" class="btn btn-primary">送出留言</button>
</form>
<% } %>
<% comments.forEach(function(comment) { %>
<div class="card" style="width: 18rem; margin-top: 10px;">
<div class="card-body">
<h5 class="card-title"><%= comment.nickname %></h5>
<p class="card-text"><%= comment.content %></p>
<% if (username === comment.username) { %>
<a class="card-link" href="/update_comment/<%= comment.id %>">編輯</a>
<a class="card-link" href="/delete_comment/<%= comment.id %>">刪除</a>
<% } %>
</div>
</div>
<% }) %>
</div>
</html>
範例:head.ejs 的程式碼
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css"
rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We"
crossorigin="anonymous">