【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,如果成功了,下一次就不会再执行迁移了

相关推荐
Bert.Cai13 小时前
MySQL CURTIME()函数详解
数据库·mysql
Bert.Cai13 小时前
MySQL CURDATE()函数详解
数据库·mysql
NGSI vimp13 小时前
MySQL|MySQL 中 `DATE_FORMAT()` 函数的使用
数据库·mysql
秋913 小时前
MySQL8.0.46 与 MySQL8.4.9:跨越代际的深度差异解析与升级全指南
mysql
HAWK eoni13 小时前
Mysql 驱动程序
数据库·mysql
xxjj998a13 小时前
Laravel4.x核心特性全解析
android·mysql·laravel
何中应13 小时前
CentOS 7安装、卸载MySQL数据库(二)
数据库·mysql·centos
梁萌14 小时前
mysql使用事件做日志表数据转移
数据库·mysql
lThE ANDE14 小时前
MySQL中的TRUNCATE TABLE命令
数据库·mysql
STER labo14 小时前
mysql配置环境变量——(‘mysql‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件解决办法)
数据库·mysql·adb