MVC是指(Model-View-Controller),是一種軟體架構模式,把軟體系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller),將應用程式的不同部分分離開來。
這樣使後續對程式的修改和擴充簡化,並且能讓程式某一部分重複利用。
除此之外,此模式透過對複雜度的簡化,也讓程式結構更加直覺。
模型代表了應用程式的資料層。它負責處理資料的讀取、寫入、驗證和操作。
在Express.js中,通常使用ORM(物件關係對映)庫(例如Mongoose)來定義模型,並與資料庫進行互動。
View(視圖):
視圖是使用者界面的部分,負責將資料呈現給使用者。視圖通常是模板文件,包含HTML和動態內容(例如資料變數)的結合。(這次不會實作到)
Controller(控制器):
控制器是應用程式的業務邏輯和控制流的中心。它處理HTTP請求,協調模型和視圖的互動,並將結果回傳給客戶端。
想了解更多請參考What is the MVC, Creating a [Node.js-Express] MVC Application
在開始前先來回顧,這是目前的posts-routes.js
const express = require('express');
const router = express.Router();
const MOCK_POSTS = [
{
id: 'p1',
title: '文章1',
content:'ChatGPT'
},
{
id: 'p2',
title: '文章2',
content:'Micro frontend'
}
]
//@router POST /api/posts
//@desc 新增文章.
//@access Public
router.post("/", (req,res,next)=>{
res.json({message: 'It works!'});
});
//@router GET api/posts/:postId
//@desc 取得文章資訊(單一).
//@access Public
router.get("/:postId",(req,res,next)=>{
const postId = req.params.postId;
const post = MOCK_POSTS.find(post =>{
return post.id === postId;
});
//若文章不存在於假資料(資料庫)
if(!post){
const error = new Error('此id的文章不存在');
error.status = 404;
throw error; //會觸發error middleware
}
res.json({post});
});
//@router PUT /api/posts/:postId
//@desc 編輯文章
//@access Public
router.put("/:postId", (req,res,next)=>{
res.json({message: 'It works!'});
});
//@router DELETE api/posts
//@desc 刪除文章
//@access Public*/
router.delete("/:postId", (req,res,next)=>{
res.json({message: 'It works!'});
});
module.exports = router;
其實可以看到我們目前只加了一個取文章資料的邏輯,整個檔案內容就明顯變多了,這時候就很適合使用Controller
來管理檔案。
Controller
負責定義和處理路由。當使用者訪問特定的URL時,Express的路由器將根據路由設置將請求導向相應的Controller
函數,這樣Controller
就可以處理該請求。
還記得上一篇在介紹的routes時,有列出他的結構
app.METHOD(PATH, HANDLER)
其中HANDLER
是當路由相符時要執行的函數,就是要擺放controller
的地方
首先我們先在資料夾底下建立一個controllers
資料夾,接著建立posts-controller.js
,
我們把posts-routes.js
裡取得文章資料api的Handler還有假資料移到posts-controller.js
裡。
//posts-controller.js
const MOCK_POSTS = [
{
id: 'p1',
title: '文章1',
content:'ChatGPT'
},
{
id: 'p2',
title: '文章2',
content:'Micro frontend'
}
]
//取得文章資料
const getPost = (req,res,next)=>{
const postId = req.params.postId;
const post = MOCK_POSTS.find(post =>{
return post.id === postId;
});
//若文章不存在於假資料(資料庫)
if(!post){
const error = new Error('此id的文章不存在');
error.status = 404;
throw error; //會觸發error middleware
}
res.json({post});
}
//將controller export出去
exports.getPost = getPost;
接著回到posts-routes.js
,來引入剛剛設置好的controller
const express = require("express");
const router = express.Router();
//引入posts-controller
const postControllers = require("../../controllers/posts-controller");
//@router GET api/posts/:postId
//@desc Get single post.
//@access Public
router.get("/:postId", postControllers.getPost);
...(略)
這樣我們的posts-routes.js
就變得乾淨很多了!
目前程式碼其實已經很簡潔了,但還有個部分可以抽出來進行處理,那就是錯誤訊息
在專案資料夾底下建立models
資料夾,並在裡面建立http-error.js
//http-error.js
class HttpError extends Error {
constructor(message, errorCode){
super(message);
this.code = errorCode;
}
}
module.exports = HttpError;
回到我們的posts-controller.js
去引入我們的modelHttpError
const HttpError = require('../models/http-error');
const getPost = (req,res,next) =>{
const postId = req.params.postId;
const post = MOCK_POSTS.find(post =>{
return post.id === postId;
});
//若文章不存在於假資料(資料庫)
if(!post){
//使用error-model
throw new HttpError('此id的文章不存在',404);
}
res.json({post});
}
https://zh.wikipedia.org/zh-tw/MVC
https://www.geeksforgeeks.org/how-to-use-get-parameter-in-express-js/