通过Koa理解MVC

  MVC 是一种常见的架构模式,它将代码分为模型(Model)、视图(View)和控制器(Controller)三部分,用来分别处理数据、响应结构和请求逻辑,能让项目结构更清晰、职责更明确,特别适合随着业务增长而逐渐复杂的后端项目。本文将通过使用 Koa 实现一个简单的用户管理接口,来理解 MVC 在实际项目中的应用。

文档和部分图片来源:MVC 模式 | 菜鸟教程

基本概念

MVC 是三个词的缩写:

  • M(Model,模型):负责“数据”,比如用户的信息从哪里来、怎么保存、怎么查。
  • V(View,视图):负责“表现”,在前后端分离项目中,可以理解为“接口返回格式”。
  • C(Controller,控制器):负责“流程”,接收请求、调用 Model 获取数据、通过 View 返回结果。

简单来说:

Controller 是中间人,它从 Model 拿数据,再用 View 包装好,返回给客户端。

代码示例

这里以一个最基础的“用户管理接口”为例,包含两个功能:

  • 获取所有用户(GET /users)
  • 添加新用户(POST /users)

模型层(models/userModel.js)

这个模块负责“数据管理”。虽然我们没有用数据库,但我们用一个数组模拟存储逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 模拟数据库
const users = []

export function createUser({ name, email }) {
const newUser = {
id: Date.now(), // 用时间戳当 ID
name,
email,
}
users.push(newUser)
return newUser
}

export function getAllUsers() {
return users
}

说明:

  • createUser 创建用户并存入内存中。
  • getAllUsers 获取所有用户。
  • 注意:Model 层不关心是哪个路由调用的,也不做任何格式化处理,它只负责“数据的获取与变更”

控制器层(controllers/userController.js)

控制器负责处理请求逻辑,比如参数校验、调用模型、返回结果等。

1
2
3
4
5
6
7
8
9
10
11
12
13
import * as userModel from '../models/userModel.js'
import { renderJSON } from '../views/jsonView.js'

export async function create(ctx) {
const { name, email } = ctx.request.body
const user = userModel.createUser({ name, email })
ctx.body = renderJSON(201, '用户创建成功', user)
}

export async function list(ctx) {
const users = userModel.getAllUsers()
ctx.body = renderJSON(200, '用户列表', users)
}

说明:

  • 控制器接收请求参数(通过 ctx.request.body 获取)。
  • 然后调用 Model 获取或处理数据。
  • 最后通过 View 模块统一格式化响应。

视图层(views/jsonView.js)

视图层在 API 项目中,最常见的用途是统一响应格式。

1
2
3
4
5
6
7
export function renderJSON(code, message, data = null) {
return {
code,
message,
data,
}
}

说明:

  • 统一格式让前端更好处理接口返回。
  • 比如:前端只需要判断 code === 200 即可,无需关心结构变化。

路由层(routes/userRoutes.js)

这一层只是把 URL 和控制器函数连接起来,不处理具体逻辑。

1
2
3
4
5
6
7
8
9
import Router from 'koa-router'
import * as userController from '../controllers/userController.js'

const router = new Router({ prefix: '/users' })

router.post('/', userController.create)
router.get('/', userController.list)

export default router

说明:

  • GET /users → 由 userController.list 处理
  • POST /users → 由 userController.create 处理

应用入口(app.js)

将所有模块组合起来:

1
2
3
4
5
6
7
8
9
10
11
12
import Koa from 'koa'
import bodyParser from 'koa-bodyparser'
import userRoutes from './routes/userRoutes.js'

const app = new Koa()

app.use(bodyParser())
app.use(userRoutes.routes())

app.listen(3000, () => {
console.log('服务已启动:http://localhost:3000')
})

小结

作用 好处
Model 管理数据 解耦业务逻辑与数据库
Controller 管理请求流程 保持接口逻辑清晰
View 格式化响应 接口结构统一,便于维护
Router 分发路径 简洁直观,职责分明

其实在写代码的过程中,哪怕没有特意的去写 MVC,我们也会因为单个代码的复杂程度增加而慢慢写出类似的分层结构,但是可能就没有这么规范了。所以与其无意识拆分还可能不够规范,我们还不如从一开始就用 MVC 架构来规范代码组织方式。

作者

Fu9Zhou

发布于

2025-05-10

许可协议