Nest.js + TypeOrm:安装、编写实体类

TypeORM 集成

$ npm install --save @nestjs/typeorm typeorm mysql2/pg

安装过程完成后,我们可以将TypeOrmModule导入到根目录中AppModule。

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [User], // 需要手动导入实体类。通过指定 autoLoadEntities: true 后,imports: [TypeOrmModule.forFeature([...])] 注册的每个实体都将自动添加到entities配置对象的数组中。
      synchronize: true, // 表格同步。用于开发测试阶段,如果表实体结构发生变化,可能自动删除、调整重建数据库表格。
    }),
  ],
})
export class AppModule {}

如果数据库配置不能是常量,可以使用异步方法:

import { Module } from '@nestjs/common';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration]
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService): Promise<TypeOrmModuleOptions> => ({
        type: 'postgres',
        host: configService.get('DB.host'),
        port: configService.get('DB.port'),
        username: configService.get('DB.username'),
        password: configService.get('DB.password'),
        database: configService.get('DB.database'),
        entities: [join(__dirname, './core') + '/**/**.entity{.ts,.js}'], // 路径通配符指定实体
        entityPrefix: 't_',
        synchronize: true
      })
    }),
  ],
  controllers: [AppController],
  providers: [AppService]
})
export class AppModule {}

实体

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @Column({
    select: false // 隐藏列
  })
  password: string;

  @Column({ default: '' })
  desc: string;

  @Column({ default: true })
  enable: boolean;

  @Column()
  roles: string;

  @Column({ type: 'jsonb', default: {} })
  permissions: object;
}

CURD

User 模块:

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UserController],
  providers: [UserService]
})
export class UserModule {}

控制器:

import { Repository } from 'typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
import { Body, Controller, Get, Inject, Logger, Post } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';

@Controller('user')
export class UserController {

    constructor(
        private readonly userService: UserService,
        @InjectRepository(User)
        private readonly usersRepository: Repository<User>,
    ) { }

    @Post("add")
    async add(@Body() user: User) {
        let result = await this.usersRepository.save(user);
        Logger.debug('添加用户', result, this.constructor.name);
        return "OK";
    }

    @Get("list")
    async list() {
        let result = await this.usersRepository.find();
        Logger.debug('查询用户', result, this.constructor.name);
        return result;
    }
}

提高密码安全性

import { Logger } from '@nestjs/common';
import * as assert from 'assert';
import * as bcrypt from 'bcrypt';
import { Entity, Column, PrimaryGeneratedColumn, BeforeInsert, BeforeUpdate } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn("increment")
  id: number;

  @Column({
    unique: true
  })
  username: string;

  @Column({
    select: false
  })
  password: string;

  /** 密码盐 */
  @Column()
  salt: string;

  @Column({ default: '' })
  desc: string;

  /** 用户是否启用 */
  @Column({ default: true })
  enable: boolean;

  @Column()
  roles: string;

  @Column({ type: 'jsonb', default: {} })
  permissions: object;

  @BeforeInsert()
  @BeforeUpdate()
  hashPassword() {
    if (!this.password) return; // 不更新密码
    let plain = this.password;
    this.salt = bcrypt.genSaltSync();
    this.password = bcrypt.hashSync(this.password, this.salt);
    Logger.debug("密码哈希", this.salt, this.password, this.constructor.name);
    assert(bcrypt.compareSync(plain, this.password));
  }
}

如果 @BeforeInsert() 等装饰器不起作用,那可能是因为 save 的不是 User 实例,而是普通对象,使用 Object.assign:

    @Post()
    async add(@Body() user: User) {
        let result = await this.usersRepository.save(Object.assign(new User(), user));
        Logger.debug('添加用户', {...result}, this.constructor.name);
        return result;
    }

或者:

    @Post()
    async add(@Body() user: User) {
        let result = await this.usersRepository.save(this.usersRepository.create(user));
        Logger.debug('添加用户', {...result}, this.constructor.name);
        return result;
    }

文档

https://docs.nestjs.com/techniques/database
https://typeorm.bootcss.com/

posted @ 2023-05-24 16:49  develon  阅读(648)  评论(1编辑  收藏  举报