上一節
5. 文章管理
5.1 新建 ev_articles 表
CREATE TABLE `my_db_01`.`Untitled` (
`Id` int(0) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL COMMENT '文章標題',
`content` text NOT NULL COMMENT '文章內容',
`cover_img` varchar(255) NOT NULL COMMENT '封面圖片',
`pub_date` varchar(255) NOT NULL COMMENT '文章發表日期',
`state` varchar(255) NOT NULL COMMENT '文章發布狀態',
`is_delete` tinyint(255) NOT NULL DEFAULT 0 COMMENT '0未洗掉,1相反',
`cate_id` int(0) NOT NULL COMMENT '分類id',
`author_id` int(0) NOT NULL COMMENT '作者id',
PRIMARY KEY (`Id`),
UNIQUE INDEX(`Id`)
) COMMENT = '文章表';
5.2 發布新文章
5.2.0 實作步驟
- 初始化路由模塊
- 初始化路由處理函式模塊
- 使用 multer 決議表單資料
- 驗證表單資料
- 實作發布文章的功能
5.2.1 初始化路由模塊
- 創建
/router/article.js路由模塊,并初始化如下的代碼結構:
// 匯入 express
const express = require('express')
// 創建路由物件
const router = express.Router()
// 發布新文章
router.post('/add', (req, res) => {
res.send('ok')
})
// 向外共享路由物件
module.exports = router
- 在
app.js中匯入并使用文章的路由模塊:
// 匯入并使用文章路由模塊
const articleRouter = require('./router/article')
// 為文章的路由掛載統一的訪問前綴 /my/article
app.use('/my/article', articleRouter)
5.2.2 初始化路由處理函式模塊
- 創建
/router_handler/article.js路由處理函式模塊,并初始化如下的代碼結構:
// 發布新文章的處理函式
exports.addArticle = (req, res) => {
res.send('ok')
}
- 修改
/router/article.js中的代碼如下:
const express = require('express')
const router = express.Router()
// 匯入文章的路由處理函式模塊
const article_handler = require('../router_handler/article')
// 發布新文章
router.post('/add', article_handler.addArticle)
module.exports = router
5.2.3 使用 multer 決議表單資料
注意:使用
express.urlencoded()中間件無法決議multipart/form-data格式的請求體資料,
當前專案,推薦使用 multer 來決議
multipart/form-data格式的表單資料,https://www.npmjs.com/package/multer
- 運行如下的終端命令,在專案中安裝
multer:
npm i [email protected]
- 在
/router_handler/article.js模塊中匯入并配置multer:
// 匯入決議 formdata 格式表單資料的包
const multer = require('multer')
// 匯入處理路徑的核心模塊
const path = require('path')
// 創建 multer 的實體物件,通過 dest 屬性指定檔案的存放路徑
const upload = multer({ dest: path.join(__dirname, '../uploads') })
- 修改
發布新文章的路由如下:
// 發布新文章的路由
// upload.single() 是一個區域生效的中間件,用來決議 FormData 格式的表單資料
// 將檔案型別的資料,決議并掛載到 req.file 屬性中
// 將文本型別的資料,決議并掛載到 req.body 屬性中
router.post('/add', upload.single('cover_img'), article_handler.addArticle)
- 在
/router_handler/article.js模塊中的addArticle處理函式中,將multer決議出來的資料進行列印:
// 發布新文章的處理函式
exports.addArticle = (req, res) => {
console.log(req.body) // 文本型別的資料
console.log('--------分割線----------')
console.log(req.file) // 檔案型別的資料
res.send('ok')
}
測驗
在認證條件下輸入cover_img,查看回傳值


5.2.4 驗證表單資料
實作思路:通過 express-joi 自動驗證 req.body 中的文本資料;通過 if 判斷手動驗證 req.file 中的檔案資料;
- 創建
/schema/article.js驗證規則模塊,并初始化如下的代碼結構:
// 匯入定義驗證規則的模塊
const joi = require('joi')
// 定義 標題、分類Id、內容、發布狀態 的驗證規則
const title = joi.string().required()
const cate_id = joi.number().integer().min(1).required()
const content = joi.string().required().allow('')
const state = joi.string().valid('已發布', '草稿').required()
// 驗證規則物件 - 發布文章
exports.add_article_schema = {
body: {
title,
cate_id,
content,
state,
},
}
- 在
/router/article.js模塊中,匯入需要的驗證規則物件,并在路由中使用:
// 匯入驗證資料的中間件
const expressJoi = require('@escook/express-joi')
// 匯入文章的驗證模塊
const { add_article_schema } = require('../schema/article')
// 發布新文章的路由
// 注意:在當前的路由中,先后使用了兩個中間件:
// 先使用 multer 決議表單資料
// 再使用 expressJoi 對決議的表單資料進行驗證
router.post('/add', upload.single('cover_img'), expressJoi(add_article_schema), article_handler.addArticle)
- 在
/router_handler/article.js模塊中的addArticle處理函式中,通過if判斷客戶端是否提交了封面圖片:
// 發布新文章的處理函式
exports.addArticle = (req, res) => {
// 手動判斷是否上傳了文章封面
if (!req.file || req.file.fieldname !== 'cover_img') return res.cc('文章封面是必選引數!')
// TODO:表單資料合法,繼續后面的處理流程...
})
5.2.5 實作發布文章的功能
以下的內容放到/router_handler/article.js的處理函式中
- 整理要插入資料庫的文章資訊物件:
// 匯入處理路徑的 path 核心模塊
const path = require('path')
//注意:放入到處理函式內
const articleInfo = {
// 標題、內容、狀態、所屬的分類Id
...req.body,
// 文章封面在服務器端的存放路徑
cover_img: path.join('/uploads', req.file.filename),
// 文章發布時間
pub_date: new Date(),
// 文章作者的Id
author_id: req.auth.id,
}
- 定義發布文章的 SQL 陳述句:
const sql = `insert into ev_articles set ?`
- 呼叫
db.query()執行發布文章的 SQL 陳述句:
// 匯入資料庫操作模塊
const db = require('../db/index')
// 執行 SQL 陳述句
db.query(sql, articleInfo, (err, results) => {
// 執行 SQL 陳述句失敗
if (err) return res.cc(err)
// 執行 SQL 陳述句成功,但是影響行數不等于 1
if (results.affectedRows !== 1) return res.cc('發布文章失敗!')
// 發布文章成功
res.cc('發布文章成功', 0)
})
- 在
app.js中,使用express.static()中間件,將uploads目錄中的圖片托管為靜態資源:
// 托管靜態資源檔案
app.use('/uploads', express.static('./uploads'))
測驗
我的踩坑點:
- 原來之所以使用
multipart/form-data的格式提交資料是因為cover_img不承認提交網路圖片鏈接的形式,而是要選擇本地檔案,不然是無法讀取到檔案型別的,點擊File即可,postman的我不清楚,

articleInfo物件中的req.user一定要改成req.auth,不然它會一直提示Cannot read properties of undefined (reading 'id')的錯誤,現在就可以看到我提交成功了,

可以看到我在uploads檔案夾中存放著以二進制流的形式存放圖片資料,

5.3 查看文章串列
/router_handler/article.js
//文章串列顯示處理函式
exports.getArticle = (req, res) => {
const sql = 'select * from ev_articles where is_delete=0 order by id asc'
db.query(sql, (err, results) => {
// 1. 執行 SQL 陳述句失敗
if (err) return res.cc(err)
// 2. 執行 SQL 陳述句成功
res.send({
status: 0,
message: '獲取文章串列成功!',
data: results,
})
})
// res.send('ok')
}
/router/article.js
// 獲取文章的串列資料
router.get('/list', article_handler.getArticle)
測驗:

5.4 根據Id洗掉文章
/router/article.js
//根據ID洗掉文章的路由
router.get('/delete/:id', expressJoi(delete_schema), article_handler.deleteById)
/router_handler/article.js
// 洗掉文章分類的處理函式
exports.deleteById = (req, res) => {
const sql = `update ev_articles set is_delete=1 where id=?`
db.query(sql, req.params.id, (err, results) => {
// 執行 SQL 陳述句失敗
if (err) return res.cc(err)
// SQL 陳述句執行成功,但是影響行數不等于 1
if (results.affectedRows !== 1) return res.cc('洗掉文章失敗!')
// 洗掉文章分類成功
res.cc('洗掉文章成功!', 0)
})
// res.send('ok')
}
/schema/article.js
// 定義 分類Id 的校驗規則
const id = joi.number().integer().min(1).required()
// 校驗規則物件 - 洗掉分類
exports.delete_schema = {
params: {
id,
},
}
注意大事件專案的art_list檔案的這個Id不要改成了id,因為資料庫里面寫的也是Id

測驗

5.5 根據Id查找文章
/router/article.js
//根據Id查詢文章
router.get(
'/:Id',
expressJoi(get_articleById_schema),
article_handler.getArticleById
)
/router_handler/article.js
//根據Id查詢文章的處理函式
exports.getArticleById = (req, res) => {
const sql = `select * from ev_articles where Id=?`
db.query(sql, req.params.Id, (err, results) => {
// 執行 SQL 陳述句失敗
if (err) return res.cc(err)
// SQL 陳述句執行成功,但是沒有查詢到任何資料
if (results.length !== 1) return res.cc('獲取文章資料失敗!')
// 把資料回應給客戶端
res.send({
success: true,
status: 0,
message: '獲取文章資料成功!',
data: results[0],
})
})
}
/schema/article.js
// 定義 文章Id 的校驗規則
const Id = joi.number().integer().min(1).required()
// 校驗規則物件 - 根據 id 獲取文章
exports.get_articleById_schema = {
params: {
Id,
},
}
測驗

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/502736.html
標籤:JavaScript
