实战使用 NestJS 搭建一个 Admin 后台服务 - 02. typeorm 操作 mysql&基础 crud

实战使用 NestJS 搭建一个 Admin 后台服务 - 01. 项目搭建、配置文件和路由

实战使用 NestJS 搭建一个 Admin 后台服务 - 02. typeorm 操作 mysql&基础 crud

上一篇已经搭建好基本的框架,本篇将开始使用 typeorm 操作 mysql 数据库,实现 crud 操作,以及入参校验。直接开整。

GitHub 项目地址,欢迎各位大佬 Star。

mysql 数据库自备

一、引入 typeorm

1、依赖安装

bash 复制代码
yarn add @nestjs/typeorm typeorm mysql2

2、配置文件修改

  • 修改 config/config.ts
ts 复制代码
export default () => ({
  port: parseInt(process.env.PORT, 10) || 3003,
  database: {
    host: process.env.DATABASE_HOST,
    port: parseInt(process.env.DATABASE_PORT, 10) || 3306,
    username: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASSWORD,
    database: process.env.DATABASE_DATABASE,
  },
});
  • 修改.env
bash 复制代码
# 端口
PORT=3003
# 数据库配置
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATABASE_USER=root
DATABASE_PASSWORD=q847164495
DATABASE_DATABASE=nest_demo # 数据库名自行设置
  • 修改 app.module.ts 文件
ts 复制代码
import { Module } from '@nestjs/common';
import { UsersModule } from './routers/users/users.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
import config from 'config/config';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    /** 环境变量配置 */
    ConfigModule.forRoot({
      isGlobal: true,
      load: [config],
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule], // 记得导入 ConfigModule
      /** 配置的使用 */
      useFactory: async (configService: ConfigService) => ({
        type: 'mysql',
        host: configService.get<string>('database.host'),
        port: configService.get<number>('database.port'),
        username: configService.get<string>('database.username'),
        password: configService.get<string>('database.password'),
        database: configService.get<string>('database.database'),
        synchronize: true,
        autoLoadEntities: true,
        timezone: '+08:00', // 东八时区
      }),
      inject: [ConfigService],
    }),
    UsersModule,
  ],
})
export class AppModule {}

二、开始基础的 crud 操作

1、修改实体类

  • 修改 users/entities/users.entity.ts
  • @Entity() 装饰类 标记为实体
ts 复制代码
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class User {
  /** 每个实体必须至少有一个主列 */
  @PrimaryGeneratedColumn()
  id: number;

  /** @CreateDateColumn 是一个特殊列,自动为实体插入日期。无需设置此列,该值将自动设置。 */
  @CreateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'create_time',
    comment: '创建时间',
  })
  createTime: Date;

  /** @UpdateDateColumn 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。无需设置此列,该值将自动设置。 */
  @UpdateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'update_time',
    comment: '更新时间',
  })
  updateTime: Date;

  @Column({ unique: true, nullable: true, comment: '用户名' })
  username: string;

  @Column({ unique: true, nullable: true, comment: '邮箱' })
  email: string;

  @Column({ unique: true, nullable: true, comment: '手机号' })
  phone: string;

  @Column({ nullable: true, comment: '头像' })
  avatar: string;

  @Column({ nullable: true, comment: '密码' })
  password: string;
}

2、创建数据库

  • 数据库名和配置一致
  • npm run start 启动项目 orm 会自动进行数据库迁移(可自行关闭)
  • 主要就是依赖 @Entity() 装饰的类

可以看到数据库里已经创建好了表

三、操作数据库进行 crud

1、module 导入

  • 修改 users/dto/create-user.dto.ts
  • users/dto/update-user.dto.ts 看情况修改,一般不需要修改
  • 下篇中参数检验需要用到
ts 复制代码
import { User } from '../entities/user.entity';

export class CreateUserDto extends User {}
ts 复制代码
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';

/** 直接继承了 且 声明为可选参数 */
export class UpdateUserDto extends PartialType(CreateUserDto) {}
  • src/types/global.d.ts 创建该文件,写全局类型
ts 复制代码
declare namespace Global {
  type RuleResType<T> = {
    code: number;
    message: string;
    data: T;
    total?: number;
  };
}
  • 修改 users.module.ts 文件
ts 复制代码
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';

@Module({
  /** 导入数据库实体类 */
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}
  • 编写 service,修改 users.service.ts 文件
ts 复制代码
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, Repository, UpdateResult } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UsersService {
  /** s实体注册 */
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  async create(
    createUserDto: CreateUserDto,
  ): Promise<Global.RuleResType<User>> {
    const { username, password, email, phone, avatar } = createUserDto;
    const data = await this.userRepository.save({
      username,
      password,
      email,
      phone,
      avatar,
    });
    return { code: 200, message: '创建成功', data };
  }

  async findAll(): Promise<Global.RuleResType<User[]>> {
    const data = await this.userRepository.find();
    return { code: 200, message: '查询成功', data };
  }

  async findOne(id: number): Promise<Global.RuleResType<User>> {
    const data = await this.userRepository.findOne({ where: { id: id } });
    return { code: 200, message: '查询成功', data };
  }

  async update(
    id: number,
    updateUserDto: UpdateUserDto,
  ): Promise<Global.RuleResType<UpdateResult>> {
    const data = await this.userRepository.update(id, updateUserDto);
    return { code: 200, message: '更新成功', data };
  }

  async remove(id: number): Promise<Promise<Global.RuleResType<DeleteResult>>> {
    const data = await this.userRepository.delete(id);
    return { code: 200, message: '删除成功', data };
  }
}
  • users.controller 暂不修改

四、接口测试

  • npm run start

  • 创建接口 注意@Column({ unique: true, nullable: true, comment: '用户名' }) 时unique 的唯一性

  • 查询接口
  • 更新
  • 删除

下一篇

本篇已经完成了基本的curd,下篇将介绍参数校验,以及使用 swagger 生成接口文档,同时直接导入apifox使用

相关推荐
㳺三才人子6 小时前
初探 Flask
后端·python·flask·html
星栈独行6 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Java爱好狂.6 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易6 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
装不满的克莱因瓶7 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl7 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
excel8 小时前
为什么我推荐使用 Termius:现代 SSH 工具的完整体验
前端·后端
卷毛的技术笔记9 小时前
Java后端硬核实战:用Spring AI Alibaba+Redis给LLM装上“超强记忆中枢”
java·人工智能·redis·后端·spring·ai·系统架构
IT_陈寒10 小时前
Java的Optional差点让我掉坑里,这几个坑你别踩
前端·人工智能·后端
子兮曰10 小时前
Harness 驾驭工程深度教程:从 AGENTS.md 到全链路 AI 编码基础设施
前端·后端·ai编程