前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >express+ts+typeorm入门

express+ts+typeorm入门

原创
作者头像
知了轻语
修改2024-08-15 16:14:12
1760
修改2024-08-15 16:14:12
举报
文章被收录于专栏:node-后端

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

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境安装
  • 包版本
  • typescript配置
  • 项目目录
  • 数据库初始化
    • 定义实体类
    • 环境变量
    • 主程序
    • 路由拆分
    • 监听文件变动
    • 启动脚本
    • 编写接口
    • 小结
    相关产品与服务
    云数据库 MySQL
    腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档