Node.js MVC + IoC/DI 架构
将 Express + Prisma + inversify 组合,实现类似 NestJS/SpringBoot 的分层架构。
核心概念
| 概念 | 说明 |
|---|---|
| MVC | Model(数据+业务逻辑)、View(视图)、Controller(协调层)三层分离 |
| IoC | 控制反转 — 组件创建和管理权交给外部容器,组件只声明依赖 |
| DI | 依赖注入 — IoC 的具体实现方式:通过构造函数/属性注入依赖 |
技术栈
bash
npm install inversify reflect-metadata inversify-express-utils
npm install prisma class-validator class-transformer| 库 | 作用 |
|---|---|
inversify | IoC/DI 容器 |
inversify-express-utils | Express + inversify 集成(@controller / @httpGet 等装饰器) |
reflect-metadata | TypeScript 装饰器元数据支持 |
class-validator + class-transformer | DTO 参数校验 |
项目结构
/src
/user
controller.ts # 路由层 — 只处理请求/响应
service.ts # 业务逻辑层 — 不碰 req/res
user.dto.ts # 数据传输对象 — 校验规则
/post/
controller.ts
service.ts
post.dto.ts
/db
index.ts # Prisma 封装
/prisma
schema.prisma
main.ts # 入口 — IoC 容器组装依赖注入流程
main.ts — IoC 容器装配
ts
import 'reflect-metadata'
import { Container } from 'inversify'
import { InversifyExpressServer } from 'inversify-express-utils'
import { UserController } from './src/user/controller'
import { UserService } from './src/user/service'
const container = new Container()
// 注入 Prisma(工厂模式)
container.bind<PrismaClient>('PrismaClient').toFactory(() => () => new PrismaClient())
container.bind(PrismaDB).toSelf()
// 注入 User 模块
container.bind(UserService).to(UserService)
container.bind(UserController).to(UserController)
// 创建 Express 服务
const server = new InversifyExpressServer(container)
server.setConfig(app => app.use(express.json()))
const app = server.build()
app.listen(3000)controller.ts — 路由 + 依赖注入
ts
import { controller, httpGet, httpPost } from 'inversify-express-utils'
import { inject } from 'inversify'
import { UserService } from './service'
@controller('/user')
export class UserController {
constructor(
@inject(UserService) private readonly userService: UserService // DI
) {}
@httpGet('/index')
async getIndex(req, res) {
res.send(await this.userService.getUserInfo())
}
@httpPost('/create')
async createUser(req, res) {
res.send(await this.userService.createUser(req.body))
}
}service.ts — 业务逻辑 + DTO 校验
ts
import { injectable, inject } from 'inversify'
import { validate } from 'class-validator'
import { plainToClass } from 'class-transformer'
@injectable()
export class UserService {
constructor(@inject(PrismaDB) private prismaDB: PrismaDB) {}
async getUserInfo() {
return this.prismaDB.prisma.user.findMany()
}
async createUser(data: UserDto) {
const user = plainToClass(UserDto, data) // 数据转换
const errors = await validate(user) // 校验
if (errors.length) return errors
return this.prismaDB.prisma.user.create({ data: user })
}
}user.dto.ts — 校验规则
ts
import { IsString, IsEmail, Length } from 'class-validator'
export class UserDto {
@IsString()
@Length(2, 20)
name: string
@IsEmail()
email: string
}分层对比
main.ts → IoC 容器(装配 Bean)
controller.ts → 路由 + 请求响应处理(无业务逻辑)
service.ts → 业务逻辑 + DTO 校验
db/index.ts → Prisma 数据库封装
prisma/schema → 数据模型定义