基于Midwayjs的管理系统-接口程序目录手册
基于 MidwayJS 4.x + Koa + TypeORM 的管理系统后端接口服务,参考 RuoYi-Vue 重构。
项目结构
mask_api_midwayjs
├── assets 静态资源(ip2region.xdb、Excel 模板)
├── docs 项目文档
├── script 部署脚本(Dockerfile、SQL、构建脚本)
├── src 源代码
│ ├── assets 运行时静态资源(构建时复制到 dist-ncc)
│ ├── config 多环境运行配置
│ ├── framework 核心通用代码
│ ├── modules 业务模块
│ ├── typings 全局类型定义
│ ├── bootstrap-bin.ts ncc 单文件打包入口
│ ├── configuration.ts Midway 框架启动入口
│ └── index.ts 模块导出入口(bundle 命令自动生成)
├── test 测试用例
├── bootstrap.js PM2 部署启动入口
├── docker-compose.yaml Docker 容器编排
├── eslint.config.js ESLint 配置
├── jest.config.js Jest 测试配置
├── package.json 依赖及启动命令
└── tsconfig.json TypeScript 配置
assets
程序内置静态资源,通过 assetsPath() 函数统一读取,由 APP_ASSETS 环境变量指定目录路径。
import { assetsPath } from "../framework/utils/assets-path";
// 读取 IP 数据库
const dbPath = assetsPath("ip2region.xdb");
// 读取 Excel 模板
const tplPath = assetsPath("template/excel", "user_import_template.xlsx");
| 环境 | APP_ASSETS 值 |
|---|---|
| 开发模式 | ./src/assets |
| ncc 构建 | ./assets |
| 测试模式 | 自动回退 cwd/src/assets |
详见 src/framework/utils/assets-path.ts 和 src/framework/utils/file/file.ts 中的 readAssetsFileStream 方法。
src/config
参考 Midway 官方-多环境配置。
| 文件 | 环境 | 说明 |
|---|---|---|
| config.default.ts | 全局 | 默认基础配置 |
| config.local.ts | local | 本地开发覆盖 |
| config.unittest.ts | unittest | 测试环境覆盖 |
一般只需修改本地开发(local)的配置文件,对默认(default)配置进行参数覆盖。生产环境通过 .env 文件注入。
src/framework
封装的核心通用代码,应用于整个程序。
framework
├── catch 全局异常捕获
├── config 配置工具
├── constants 常量定义
├── datasource 数据源封装(数据库 + Redis)
├── ip2region IP 归属地查询
├── middleware 中间件
├── reqctx 请求上下文
├── resp 响应封装
├── token JWT 令牌处理
└── utils 工具函数
├── assets-path.ts 资源路径解析
├── crypto 加密工具
├── date 日期工具
├── file 文件工具(上传、读取、Excel)
├── generate 生成工具(验证码、随机码)
├── parse 解析工具
├── regular 正则工具
└── ua 浏览器 UA 工具
catch — 全局异常捕获
统一拦截异常并格式化响应:
| 异常 | 说明 |
|---|---|
ForbiddenError | 403 当前操作没有权限 |
UnauthorizedError | 401 未授权认证用户 |
NotFoundError | 404 页面未找到 |
validate_error | 422 参数校验失败 |
error_catch | 500 未知异常 |
datasource — 数据源封装
datasource/db/— TypeORM 数据库连接,支持原生 SQL 执行datasource/redis/— Redis 缓存连接
ip2region — IP 归属地
根据 IP 地址查询归属地信息,数据文件为 assets/ip2region.xdb。
middleware — 中间件
| 中间件 | 说明 |
|---|---|
report.ts | 请求响应日志记录 |
authorize_user.ts | 用户身份授权校验 |
operate_log.ts | 操作日志记录 |
repeat_submit.ts | 防重复提交 |
rate_limit.ts | 接口限流 |
reqctx — 请求上下文
请求级别的上下文信息处理,获取当前登录用户、客户端 IP 等。
resp — 响应封装
统一的响应数据结构封装。
token — JWT 令牌
JWT 令牌的生成、刷新、解析处理。
utils — 工具函数
仅依赖 npm 库,不与框架绑定的纯函数工具。
src/modules
按功能领域划分模块,每个模块遵循分层架构。
modules
├── auth 认证模块(登录、登出、令牌刷新)
│ ├── controller 接口路由
│ ├── model 数据模型
│ └── service 业务逻辑
├── common 通用模块(验证码、通用接口)
│ └── controller
├── demo 示例模块
│ ├── controller
│ ├── model
│ └── service
├── monitor 监控模块(在线用户、定时任务、服务监控)
│ ├── controller
│ ├── model
│ ├── processor 队列任务处理
│ ├── repository
│ └── service
└── system 系统模块(用户、角色、菜单、部门、字典等)
├── controller
├── model
│ └── vo 视图对象
├── repository
└── service
分层说明
| 层 | 目录 | 职责 |
|---|---|---|
| 控制层 | controller | 定义路由,接收验证参数,调用 service |
| 数据模型 | model | 数据库表字段映射,或业务数据结构 |
| 视图对象 | model/vo | 接口响应的数据结构定义 |
| 业务逻辑 | service | 核心业务处理,条件判断、依赖调用 |
| 数据存储 | repository | 数据库 CRUD 操作,事务处理 |
| 队列处理 | processor | BullMQ 异步任务处理 |
controller 示例
import { Controller, Get, Inject } from "@midwayjs/core";
import { PreAuthorize } from "../../framework/decorator/authorize_user";
import { RateLimit } from "../../framework/middleware/rate_limit";
@Controller("/system/user")
export class SysUserController {
@Inject()
private sysUserService: SysUserService;
@Get("/list")
@PreAuthorize({ hasPermissions: ["system:user:list"] })
@RateLimit({ time: 60, count: 100 })
async list() {
return await this.sysUserService.list();
}
}
数据库事务
使用 TypeORM QueryRunner 管理事务:
import { Inject, Provide, Singleton } from "@midwayjs/core";
import { DataSource } from "typeorm";
@Provide()
@Singleton()
export class SysUserRepository {
@Inject()
private dataSource: DataSource;
async transferAmount(fromId: number, toId: number, amount: number): Promise<boolean> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
await queryRunner.query("UPDATE sys_user SET balance = balance - ? WHERE id = ?", [amount, fromId]);
await queryRunner.query("UPDATE sys_user SET balance = balance + ? WHERE id = ?", [amount, toId]);
await queryRunner.commitTransaction();
return true;
} catch (err) {
await queryRunner.rollbackTransaction();
throw new Error("服务数据异常");
} finally {
await queryRunner.release();
}
}
}
队列任务处理
import { Processor, IProcessor } from "@midwayjs/bullmq";
@Processor("simple")
export class SimpleProcessor implements IProcessor {
async execute(options: any) {
// options 获取任务执行时传入的参数
// 返回结果用于记录执行结果
return options;
}
}
src/typings
全局类型定义。
| 文件 | 说明 |
|---|---|
commont.ts | 通用类型声明 |
entities.ts | TypeORM 实体注册列表(打包需要显式注册) |
processor.ts | 队列处理器类型 |
test
Jest 测试用例。
npm run test # 运行测试
npm run cov # 测试覆盖率