express+ts+typeorm入门

2024-08-15 16:14:12 浏览数 (3)

express 是node生态中非常优秀的框架,大部分的业务接口,我们都可以通过它来实现。

有时候我们想使用 typescript开发业务,然后使用 typeorm 链接我们的 mysql 数据库, 应该怎么创建我们的项目呢?

在使用 typeorm 的时候, 可能很多人看到这个 ORM 大部分使用的 装饰器, 今天我们用 express去集成一下

纯的用 typeorm 可能你没有啥问题, 但是 typescript typeorm 集成可能会出现各种各样的 bug, 今天手把手我们一起实践

注:纯 js版本写 typeorm 的 实体也是可以的, 不一定要写 装饰器的class 定义实体

我们现在开始吧!

环境安装

代码语言:shell复制
pnpm init

pnpm add express -S
pnpm add @types/express typescript @types/node -D

# 安装 typeorm
pnpm add typeorm reflect-metadata -S

# 数据库
pnpm add mysql2 -S

# 安装 `ts-node` 支持在 开发环境运行 ts 代码
# 安装 `nodemon` watch文件的变动
pnpm add ts-node nodemon -D

包版本

编写本文,所有包均为最新

代码语言:json复制
{
  "scripts": {
    "dev": "cross-env NODE_ENV=development nodemon --exec 'ts-node' src/app.ts",
    "local:prod": "cross-env NODE_ENV=production node dist/app.js",
    "build": "tsc"
  },
  "dependencies": {
    "cors": "^2.8.5",
    "dotenv": "^16.4.5",
    "express": "^4.19.2",
    "mysql2": "^3.11.0",
    "reflect-metadata": "^0.2.2",
    "typeorm": "^0.3.20"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "@types/node": "^22.2.0",
    "cross-env": "^7.0.3",
    "nodemon": "^3.1.4",
    "prettier": "^3.3.3",
    "ts-node": "^10.9.2",
    "typescript": "^5.5.4"
  }
}

typescript配置

代码语言:shell复制
# 初始化一个配置文件
npx tsc --init

将装饰器相关的配置启用

  • experimentalDecorators, emitDecoratorMetadata
  • strictPropertyInitialization 设置为false, 避免在写实体类的时候,没有给属性初始化,然后出现警告
代码语言:json复制
{
  "compilerOptions": {
       "experimentalDecorators": true,
       "emitDecoratorMetadata": true,
        "allowJs": true,
       "strictPropertyInitialization": false, 
        "rootDir": "./src",
        "baseUrl": "./",
        "outDir": "./dist",
        "esModuleInterop": true
  }
}

不要动 target, module, moduleResolution 配置, 就默认注释掉就行;

否则 在dev 阶段,会出现各种 ts-node无法解析ts文件的问题

项目目录

创建基础的项目目录, app.ts 为程序主入口

代码语言:shell复制
- src
    - config     配置文件
      - db.ts
    - controller 路由文件
      - index.ts
      - user.ts
      - permission.ts
      - ....
    - db         数据库相关
       - datasource.ts 数据库初始化
    - entity     数据库实体
       - Factory.ts  测试使用的
    - service    逻辑处理
    - app.ts     程序主入口
- package.json
- nodemon.json   nodemon.json配置文件
- .gitignore
- .env
- .env.development
- .env.production

数据库初始化

src/db/datasource.ts

代码语言:ts复制
import { DataSource } from 'typeorm'
import config from '../config/db'

export const dataSource = new DataSource(config)

src/config/db.ts

代码语言:ts复制
import { type DataSourceOptions } from 'typeorm'
import { Factory } from '../entity/Factory'

const config: DataSourceOptions = {
  type: 'mysql',
  host: 'localhost',
  port: 3306,
  username: 'root',
  password: '123456',
  database: 'blog',
  entities: [Factory],
  // 是否自动同步
  synchronize: true
}

export default config
定义实体类

src/entity/Factory.ts

代码语言:ts复制
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'

@Entity()
export class Factory {
  @PrimaryGeneratedColumn('increment', {
    comment: '工厂id'
  })
  id: number

  @Column({
    comment: '工厂名称',
    type: 'varchar',
    length: 150
  })
  name: string

  @Column({
    type: 'varchar',
    length: 255,
    comment: '工厂地址'
  })
  address: string
}

环境变量

在不同的环境,我们需要加载不同的配置文件,使用 env 进行管理

代码语言:shell复制
pnpm add dotenv -S
pnpm add cross-env -D

.env 编写通用的内容

.env.development 开发环境

代码语言:shell复制
PORT=3000

.env.production 生产环境

代码语言:shell复制
PORT=4000

主程序

  • PORT 是 env 里面拿到的
代码语言:ts复制
import 'reflect-metadata'
import express from 'express'

// 加载数据库
import { dataSource } from './db/datasource'
import router from './controller'

import dotenv from 'dotenv'

console.log('当前环境', process.env.NODE_ENV)

dotenv.config({
  path: ['.env', '.env.'   process.env.NODE_ENV]
})

const app = express()

// 数据库初始化
dataSource
  .initialize()
  .then(() => {
    // 需要再数据库初始化完成后才去初始化server 服务,避免在server服务中有一些 定时任务,或者其他的直接就调用 数据库操作,导致偶发报错
    // 因为异步问题,偶发报错就不好排查
    app.use('/api', router)

    app.listen(process.env.PORT, () => {
      console.log('服务启动, http://localhost:'   process.env.PORT)
    })
  })
  .catch((e) => {
    console.log('数据库启动失败')
    console.log(e)
  })
  • 接口的 api 前缀是在这里指定的。

路由拆分

我们在 src/controller/index.ts 中编写路由

代码语言:ts复制
/**
 * 统一维护路由
 */

import express from 'express'

const router = express.Router()

import user from './user'
import permission from './permission'

router.use('/user', user)
router.use('/permission', permission)

export default router

src/controller/permission.ts

代码语言:ts复制
import express from 'express'

const router = express.Router()

// http://localhost:3000/api/permission/getMenu
router.get('/getMenu', (req, res) => {
  res.json({
    code: 0,
    data: null,
    message: 'success'
  })
})

// http://localhost:3000/api/permission/menu
router.post('/menu', (req, res) => {
  res.json({
    code: 0,
    data: null,
    message: 'success'
  })
})

export default router

其他路由文件,照葫芦画瓢即可。

现在路由都规划好了,需要集成到 应用中

src/app.ts

代码语言:ts复制
import router from './controller'

const app = express()

... 省略了其他代码
app.use('/api', router)

监听文件变动

开发阶段,我们需要监听文件变动,自动重启服务; 使用 nodemon比较轻松的做到这一点

在根目录创建配置文件

nodemon.json

代码语言:json复制
{
  "watch": [
    "src"
  ],
  "ext": "js,ts"
}

启动脚本

上面所有流程都做了以后,我们已经从项目的 初始化依赖安装路由规划环境变量加载等等,完成了一个项目的 90%, 现在需要编写我们的 启动脚本

package.json

代码语言:json复制
{
  "scripts": {
    "dev": "cross-env NODE_ENV=development nodemon --exec 'ts-node' src/app.ts",
    "local:prod": "cross-env NODE_ENV=production node dist/app.js",
    "build": "tsc"
  },
}
  • 脚步执行过程中,我们需要注入 NODE_ENV ,以区分不同的环境
  • 使用 nodemon 监听我们的文件变动,从而重启服务 然后将 ts-node 作为子进程执行
  • ts-node 会自动读取到 项目的根目录的 tsconfig.json 配置文件,然后执行主入口 src/app.ts 程序
  • 在生产环境, 我们应该先执行 build 将typescript 编译为 js文件,然后再执行 local:pord 脚步,启动项目
  • package.json中的type:'module' 字段不要加

编写接口

现在,我们简单的编写一个接口,测试数据的写入

src/controller/user.ts

代码语言:ts复制
import express from 'express'
import { dataSource } from '../db/datasource'
import { Factory } from '../entity/Factory'

const factory = dataSource.getRepository(Factory)
const router = express.Router()

router.get('/', async (req, res) => {
  // 测试代码
  await factory.save({
    name: '测试工厂',
    address: '测试地址'
  })

  res.json({
    code: 0,
    data: null,
    message: 'success'
  })
})


export default router

访问地址: http://localhost:3000/api/user

数据写入成功

小结

至此, 你已经掌握了一个简单的后台项目如何搭建,项目结构如何组织,路由管理等基础知识。

大型项目会有更多的内容,比如 日志管理, CORS, 鉴权等等, 这些都是在一点一点的叠加的,只要掌握了基础的内容,我们就能自行 添砖加瓦

项目模板地址: https://gitee.com/luoriwusheng/express-ts-typeorm-template.git

如果你有任何问题,欢迎留言,我们一起探讨~

0 人点赞