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/