# typescript-express-template **Repository Path**: w-kev/typescript-express-template ## Basic Information - **Project Name**: typescript-express-template - **Description**: TypeScript + Routing Controllers + Express API Server - **Primary Language**: TypeScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-08-04 - **Last Updated**: 2025-09-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基于 TS + Express + Prisma + MySQL + Redis + Swagger 的后端项目模板 ## 项目简介 这是一个基于 TypeScript + Express + Prisma + MySQL + Redis + Swagger 的后端项目模板,用于快速开发一个完整的后端项目。 ## 项目结构 ``` ├── plop-template/ # 模块模板目录 │ ├── dto/ # 数据传输对象模板 │ ├── interfaces/ # 数据传输对象接口模板 │ ├── module/ # 控制层 和 数据服务层骨架模板 ├── prisma/ # Prisma ORM 相关 │ ├── migrations/ # 数据库迁移记录目录 │ ├── seed/ # 种子数据脚本(初始化测试/演示数据) │ ├── ├── runner.ts # 运行所有种子文件 │ ├── ├── abstract.ts # 抽象类模板 │ ├── ├── / # 模块名称 │ ├── ├── ├── .data.ts # 待初始化数据源文件 │ ├── ├── ├── .seed.ts # 模块的种子数据脚本文件 │ └── schema.prisma # 数据库模型定义文件 ├── src/ # TypeScript 业务源码 │ └── config/ # 全局配置(数据库、Redis、日志等环境变量的获取与导出) │ └── controllers/ # 路由控制器(接收请求 → 调用 service → 返回响应) │ └── database/ # 数据库连接初始化、事务封装等 │ └── decorators/ # 自定义装饰器(如路由守卫、权限、验证装饰器) │ └── dtos/ # Data Transfer Object,接口请求/响应的数据模型定义 │ └── exceptions/ # 自定义异常类(统一异常处理) │ └── generated/ # Prisma 自动生成的客户端代码(不手写) │ └── http/ # HTTP 客户端封装(如 axios 实例、通用请求方法) │ └── interfaces/ # TypeScript 接口定义(不含业务逻辑,仅类型约束) │ └── logs/ # 本地日志文件目录 │ └── middlewares/ # Express 中间件(鉴权、日志、错误处理、速率限制等) │ └── services/ # 业务逻辑层(数据库交互、第三方 API 调用、复杂计算等) │ └── test/ # 单元测试 & 集成测试文件 │ └── utils/ # 工具函数(日期处理、加密、文件操作等公共方法) │ └── app.ts # Express 应用实例(注册中间件、路由) │ └── server.ts # 应用启动入口(监听端口) ├── .dockerignore # 构建 Docker 镜像时排除的文件列表 ├── .editorconfig # 跨编辑器的代码风格统一配置 ├── .env # 通用环境变量 ├── .env.development.local # 本地开发专属环境变量(覆盖 .env) ├── .env.production.local # 生产环境专属环境变量 ├── .env.test.local # 测试环境专属环境变量 ├── .eslintrc # ESLint 代码规范配置 ├── .gitignore # Git 忽略文件列表 ├── .huskyrc # Husky Git 钩子配置 ├── .lintstagedrc.json # lint-staged 配置(只对 Git 暂存区文件做 lint) ├── .prettierrc # Prettier 代码格式化规则 ├── .swcrc # SWC 编译器配置(替代 tsc/babel 的高性能方案) ├── docker-compose.yml # 多容器编排(本地开发一键起服务) ├── Dockerfile.dev # 开发环境 Docker 镜像构建脚本 ├── Dockerfile.prod # 生产环境 Docker 镜像构建脚本 ├── ecosystem.config.js # PM2 部署/进程守护配置 ├── eslint.config.js # ESLint 新格式配置(与 .eslintrc 二选一) ├── jest.config.js # Jest 单元测试配置 ├── Makefile # 常用脚本命令聚合(如 make dev / make build) ├── nginx.conf # Nginx 反向代理/静态资源托管配置 ├── nodemon.json # nodemon 开发热重启配置 ├── package.json # Node 项目元数据、依赖、脚本 ├── package-lock.json # NPM 依赖锁版本 ├── plopfile.js # Plop 模板生成器配置(快速创建模块骨架) ├── README.md # 项目说明文档 ├── sql.md # 数据库脚本/表结构说明文档 ├── tsconfig.json # TypeScript 编译配置 ├── yarn.lock # Yarn 依赖锁版本 ``` ## 功能介绍 - [x] 单双 Token 验证 - [x] 系统操作日志 - [x] 根据业务代码自动生成相关的api接口文档。 - [ ] 颗粒度精确到模块的权限控制 ## 运行环境 - Node.js >= 20.17 - MySQL >= 8.0 - Redis >= 5.0 ## 快速开始 1. 安装 Yarn ```bash npm install -g yarn ``` 2. 安装依赖包 ```bash yarn ``` 3. 配置数据库连接 在 `.env` 文件中配置 `MySQL` 和 `Redis` 的数据库连接信息。 4. 运行项目 ```bash yarn dev ``` ## 数据库操作 1. 初始化 Prisma ```bash npx prisma init ``` 2. 迁移数据库 迁移 ```bash npx prisma migrate dev --name ``` 同步 ```bash npx prisma db push ``` 3. 生成 Prisma Client ```bash npx prisma generate ``` 如需重置数据库,请按顺序执行以下命令: ```bash # 1. 重置迁移文件(会清除数据库所有表与数据) npx prisma migrate reset # 2. 生成迁移文件(该步骤会自动生成Prisma数据库表实例) npx prisma migrate dev --name init ``` 执行初始化种子文件 > 执行种子文件之前需要先执行 `prisma generate` 确保生成 `Prisma Client` 初始化所有种子文件 ```bash npx ts-node prisma/seed/runner.ts ``` 单独执行指定种子文件 > 如:npx ts-node prisma/seed/role/role.seed.ts ```bash npx ts-node prisma/seed//.seed.ts ``` ## 异常处理系统 一套完整的异常处理系统,专门用于处理登录和权限相关的错误。 ### 异常类分类 #### 1. 基础异常 - `HttpException`: 所有异常的基类 #### 2. 认证相关异常 (auth.exception.ts) ##### 用户相关 - `InvalidCredentialsException`: 账号或密码错误 - `UserNotFoundException`: 用户不存在 - `UserDisabledException`: 用户被禁用 - `UserAlreadyExistsException`: 用户已存在 - `EmailAlreadyExistsException`: 邮箱已存在 ##### Token相关 - `UnauthorizedException`: 未授权 - `TokenMissingException`: Token缺失 - `TokenInvalidException`: Token无效 - `TokenExpiredException`: Token已过期 - `RefreshTokenMissingException`: 刷新Token缺失 - `RefreshTokenInvalidException`: 刷新Token无效 - `RefreshTokenExpiredException`: 刷新Token已过期 ##### 登录相关 - `LoginFailedException`: 登录失败 - `TooManyLoginAttemptsException`: 登录尝试次数过多 - `AccountLockedException`: 账户被锁定 - `AccountDisabledException`: 账户被禁用 ##### 其他 - `PermissionException`: 权限校验失败 - `SystemConfigurationException`: 系统配置错误 #### 3. 权限相关异常 (permission.exception.ts) ##### 角色权限 - `RoleNotFoundException`: 角色不存在 - `RoleNotAssignedException`: 用户未分配角色 - `RoleDisabledException`: 角色被禁用 ##### 系统权限 - `ForbiddenException`: 无权限 ##### 其他权限 - `MaintenanceModeException`: 系统维护中 - `IPRestrictedException`: IP地址受限 #### 字典相关异常(dict.exception.ts) - `DictNotFoundException`: 字典不存在 - `DictNotAllowedToDeleteException`: 内置字典不允许删除 - `DictNotAllowedToUpdateException`: 内置字典不允许更新 #### 角色相关异常(role.exception.ts) - `RoleNotFoundException`: 角色不存在 #### 部门相关异常(department.exception.ts) - `DepartmentNotFoundException`: 部门不存在 ### 使用方法 #### 1. 导入异常类 ```typescript // 导入单个异常类 import { UserNotFoundException } from '@exceptions/auth.exception'; // 导入多个异常类 import { UnauthorizedException, ForbiddenException } from '@exceptions'; // 导入所有异常类 import * as Exceptions from '@exceptions'; ``` #### 2. 在服务中使用 ```typescript import { UserNotFoundException, PasswordMismatchException } from '@exceptions'; export class AuthService { async login(username: string, password: string) { const user = await this.findUser(username); if (!user) { throw new UserNotFoundException('用户名或邮箱不存在'); } if (!user.status) { throw new UserDisabledException('用户已被禁用'); } const isValidPassword = await this.validatePassword(password, user.password); if (!isValidPassword) { throw new PasswordMismatchException('密码错误'); } // 登录成功逻辑... } } ``` #### 3. 在中间件中使用 ```typescript import { UnauthorizedException, TokenExpiredException } from '@exceptions'; export const authMiddleware = async (req: any, res: any, next: any) => { try { const token = req.headers.authorization; if (!token) { throw new UnauthorizedException('请先登录'); } const decoded = await verifyToken(token); if (!decoded) { throw new TokenExpiredException('Token已过期,请重新登录'); } req.user = decoded; next(); } catch (error) { next(error); } }; ``` #### 4. 在控制器中使用 ```typescript import { ForbiddenException, AdminOnlyException } from '@exceptions'; export class UserController { async createUser(req: any, res: any) { const currentUser = req.user; // 检查管理员权限 if (!this.isAdmin(currentUser)) { throw new AdminOnlyException('只有管理员可以创建用户'); } // 创建用户逻辑... } async getUser(req: any, res: any) { const userId = req.params.id; const currentUser = req.user; // 检查权限 if (currentUser.id !== parseInt(userId) && !this.isAdmin(currentUser)) { throw new ForbiddenException('只能查看自己的信息'); } // 获取用户信息... } } ``` ### HTTP状态码映射 | 异常类 | HTTP状态码 | 说明 | |-------------------------------|---------|--------| | BadRequestException | 400 | 请求参数错误 | | UnauthorizedException | 401 | 未认证 | | ForbiddenException | 403 | 无权限 | | UserNotFoundException | 404 | 用户不存在 | | UserAlreadyExistsException | 409 | 用户已存在 | | TooManyLoginAttemptsException | 429 | 请求过于频繁 | | AccountLockedException | 423 | 账户被锁定 | | SystemConfigurationException | 500 | 系统配置错误 | | MaintenanceModeException | 503 | 系统维护中 | ### 扩展异常类 如果需要添加新的异常类,请遵循以下规范: 1. 继承 `HttpException` 基类 2. 选择合适的HTTP状态码 3. 提供有意义的默认消息 4. 支持自定义消息参数 5. 在相应的异常文件中添加 6. 在 `src/exceptions/index.ts` 中导出 ```typescript export class CustomException extends HttpException { constructor(message: string = '自定义异常消息') { super(400, message); } } ```