【node后端】搭建项目(Express+Ts+Typeorm+Mysql一步到位)

前言

必须全局安装typeorm命令

typescript 复制代码
npm i typeorm -g

使用typeorm初始化项目

通过这种方式默认会安装typeorm和ts相关的内容,以及实体类和控制器以及热更新操作

typescript 复制代码
typeorm init --name MyProject --database mysql --express --module esm

这里面的database还可以用其他数据库

安装依赖

typescript 复制代码
pnpm i

安装其他依赖

这个时候还需要安装其他依赖项

typescript 复制代码
pnpm add routing-controllers 
pnpm add @types/express @types/body-parser -D

修改模板

删除原有文件的Controller和entity文件,删除route.ts文件

修改tsconfig.json

plain 复制代码
{
   "compilerOptions": {
      "lib": [
         "es2021"
      ],
      "target": "es2021",
      "module": "es2022",
      "esModuleInterop": true,
      "moduleResolution": "node",
      "allowSyntheticDefaultImports": true,
      "outDir": "./build",
      "emitDecoratorMetadata": true,
      "experimentalDecorators": true,
      "sourceMap": true
   }
}

配置数据库

data-source.ts文件中

typescript 复制代码
import "reflect-metadata"
import { DataSource } from "typeorm"

export const dataSource = new DataSource({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "root",
    password: "123456",
    database: "cjh_test",
    synchronize: true,
    logging: false,
    entities: [
        "entity/*.ts"
    ],
     subscribers: [
        "subscriber/*.ts"
    ],
    migrations: [
        "migration/*.ts"
    ]
})

新增实体类(数据库映射)

在entity目录下新建Article.ts文件

typescript 复制代码
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity('article')
export class Article{
 @PrimaryGeneratedColumn()
  id!: number

  //指定在数据库的实际名称
  @Column({name:'job_no'})
  jobNo!: string

  @Column()
  title!: string

  //指定在数据库中的类型
  @Column('text')
  content!: string


  @Column({ name: 'created_by' })
  createdBy!: string
 
  @Column({ type: 'date', name: 'created_at' })
  createdAt!: string
 
  @Column({ name: 'updated_by' })
  updatedBy!: string
 
  @Column({ type: 'date', name: 'updated_at' })
  updatedAt!: string

}

这里我创建了一个Article实体类

推荐使用命令来创建一个空的实体类

typescript 复制代码
typeorm entity:create src/entity/Article

新增服务层(操作数据库)

我们在src下创建一个service目录,并新建article.service.ts文件

typescript 复制代码
/**
 * 文章服务类
 */
import {dataSource} from '../data-source'
import { Article } from '../entity/Article'
 
export class ArticleService {
  articleRepository
  constructor() {
    this.articleRepository = dataSource.getRepository(Article)
  }
  // 查询全部文章
  async queryAllArticle() {
    return await this.articleRepository.findAndCount()
  }
}

新增控制层(业务层)

我们在src下的controller目录中,新建article.controller.ts文件

typescript 复制代码
/**
 * 文章 controller
 */
import { Controller, Get } from "routing-controllers";
import { ArticleService } from "../services/article.service.js";

//公共前缀
@Controller("/article")
export class ArticleController {
  articleService;
  constructor() {
    this.articleService = new ArticleService();
  }

  //实际请求 /article/queryArticleList
  @Get("/queryArticleList")
  queryArticleList() {
    return this.articleService.queryAllArticle();
  }
}

修改入口文件

修改index.ts

typescript 复制代码
import express from "express";
import bodyParser from "body-parser";
import { AppDataSource } from "./data-source.js";
import { ArticleController } from "./controller/article.controller.js";
import { BaseController } from "./controller/base.controller.js";
import { useExpressServer } from "routing-controllers";
const { json, urlencoded } = bodyParser;
function init() {
  AppDataSource.initialize()
    .then(async () => {
      console.log("Data Source has been initialized!");
    })
    .catch((error) => console.log(error));

  const app = express();

  // body 解析相关中间件
  // 解析 json 格式
  app.use(json());
  // 解析 urlencoded body
  // 会在 request 对象上挂载 body 属性,包含解析后的数据。
  // 这个新的 body 对象包含 key-value 键值对,若设置 extended 为 true,则键值可以是任意累心个,否则只能是字符串或数组。
  app.use(urlencoded({ extended: true }));

  // 将当前实例注册到 routing-controllers
  useExpressServer(app, {
    controllers: [BaseController, ArticleController],
  });

  app.listen(3000, () => {
    console.log(`  App is running at http://localhost:3000\n`);
    console.log("  Press CTRL-C to stop\n");
  });
}

init();

补充一个初始控制器

typescript 复制代码
import { Controller, Get } from "routing-controllers";


@Controller('/')
export class BaseController {
  constructor() {}

  @Get('/')
  async index() {
    return 'hello world'
  }
}

运行

typescript 复制代码
npm start

这个时候你会看到hello world

生成空白迁移文件模版并运行

这一步可以自动帮我们建表

创建迁移文件

typescript 复制代码
typeorm migration:create src/migration/ArticleTable 
typescript 复制代码
import { MigrationInterface, QueryRunner } from "typeorm";

export class ArticleTable1748858082419 implements MigrationInterface {

    public async up(queryRunner: QueryRunner): Promise<void> {
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
    }

}

这样就会生成一份迁移文件,up就是更新数据,down就是删除数据

执行迁移文件

typescript 复制代码
npx typeorm-ts-node-esm migration:run -d ./src/data-source.ts

回滚

typescript 复制代码
typeorm migration:revert

使用验证模块

vue 复制代码
npm install class-validator --save

实体类生成迁移文件

这里我们根据实体类生成了迁移文件

plain 复制代码
"scripts": {
      "start": "node --loader ts-node/esm src/index.ts",
      "typeorm": "typeorm-ts-node-esm",
      "send": "node --loader ts-node/esm public/send.ts",
      "receive": "node --loader ts-node/esm public/receive.ts"
   }
typescript 复制代码
npm run typeorm -- migration:generate src/migration/SysLogsDefault -d ./src/data-source.ts

注意要点

必须显式的明确文件后缀

注意tsconfig.json文件 "esModuleInterop": true

执行迁移文件的时候,会记录一次迁移id,如果成功了,下一次就不会再执行迁移了

相关推荐
止水编程 water_proof39 分钟前
MySQL——事务详解
数据库·mysql
不似桂花酒1 小时前
数据库小知识
数据库·sql·mysql
ZZH1120KQ2 小时前
ORACLE的表维护
数据库·oracle
典孝赢麻崩乐急2 小时前
数据库学习------数据库事务的特性
数据库·学习·oracle
Warren982 小时前
MySQL查询语句详解
java·开发语言·数据库·mysql·算法·蓝桥杯·maven
多读书1932 小时前
MYSQL:JDBC编程
数据库·mysql
孫治AllenSun5 小时前
【Mysql】联合索引生效分析案例
java·数据库·mysql
蓝黑20205 小时前
MySQL的case
数据库·mysql
Debug笔记6 小时前
MySQL 慢查询优化实战:看懂执行计划,性能提升 10 倍不是梦。
mysql
翔云1234567 小时前
MySQL 高并发下如何保证事务提交的绝对顺序?
数据库·mysql