十二、基于基类CURD(nestjs+next.js从零开始一步一步创建通用后台管理系统)

173 阅读3分钟

开发中,很多实体对象(如用户、订单、商品等)都需要实现基本的创建(Create)、读取(Read)、更新(Update)、删除(Delete)功能,也就是 CURD 操作。以用户管理系统为例,如果没有 CURD 基类,每个具体的实体类(如管理员用户类、普通用户类等)都要自己编写创建用户、查询用户、更新用户信息、删除用户等方法。这样会导致大量的重复代码。创建 CURD 基类后,这些通用的 CURD 方法可以集中定义在基类中,各个实体子类只需继承基类,就可以直接使用这些方法,大大减少了代码的冗余。

目录 1、创建基础实体类 2、创建服务器基类 3、创建控制器基类 4、使用基类示例

1、创建基础实体类

实体基类可以包括一些每个表都有的字段,如主键id,创建人、创建日期、备注等字段。

//base/base.entity.ts
import { Column, Entity, Int32, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class BaseEntity{
  @PrimaryGeneratedColumn({type: 'int'})
  id: number;

  @Column()
  createdAt:  Date;

  @Column()
  updatedAt:  Date;
}

2、创建服务器基类

注意:构造函数未使用 @InjectRepository注解,我们会在继承种使用该注解,并使用super函数调用基类种的构造函数。

//base/base.service.ts
import { Injectable } from '@nestjs/common';
import { DeleteResult, Repository, UpdateResult } from 'typeorm';

@Injectable()
export abstract class BaseService<T> {
  
  constructor(
    protected repository: Repository<T>,
  ) {
  }

  async findAll(): Promise<T[]> {
    return this.repository.find();
  }

  async findOne(id: number): Promise<T> {
    const record = await this.findOne(id);
    if (!record) throw new Error('Record not found');
    return record;
  }

  async create(data: Partial<T>): Promise<T[]> {
    return this.repository.create(data as any);
  }

  async update(id: number, data: Partial<T>): Promise<UpdateResult> {
    return this.repository.update(id, data as any);
  }

  async delete(id: number): Promise<DeleteResult> {
    return this.repository.delete(id);
  }
}

3、创建控制器基类

//base/base.controller.ts
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';

@Controller()
export abstract class BaseController<T> {
  constructor(protected readonly service: any) {}

  @Get()
  findAll() {
    return this.service.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.service.findOne(+id);
  }

  @Post()
  create(@Body() data: any) {
    return this.service.create(data);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() data: any) {
    return this.service.update(+id, data);
  }

  @Delete(':id')
  delete(@Param('id') id: string) {
    return this.service.delete(+id);
  }
}

4、使用基类示例

4.1、创建模块

使用下面指令创建一个test模块。

nest g res test --no-spec

4.2、修改实体基类

让实体基类继承自基类,通用字段就可以省略了。

// test.entity.ts
import { BaseEntity } from 'src/base/base.entity';
import { Entity, Column } from 'typeorm';

@Entity("test")
export class Test extends BaseEntity{
  @Column()
  name: string;

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

4.3、修改服务类

修改服务类,继承自BaseService,这样基础的CURD功能就具备了。注意构造函数中必须要有super调用父类。此处我们新增加了一个方法findTest,也可以用同名方式覆盖基类中的方法。

// test.service.ts
import { Injectable } from '@nestjs/common';
import { Test } from './entities/test.entity';
import { BaseService } from 'src/base/base.service';
import { UpdateTestDto } from './dto/update-test.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { EntitySchema, Repository } from 'typeorm';
@Injectable()
export class TestService extends BaseService<Test> {
  
  constructor(
    @InjectRepository(Test)
    protected repository: Repository<Test>,
  ) {
    super(repository);
  }

 async findTest(): Promise<UpdateTestDto[]> {
    const bb= await this.repository.find();
    return bb;
  }
}

4.4、修改控制器

让控制器继承自基类,并调用super方法。新增加一个findTest接口用于测试。

// test.controller.ts
import { Controller, Get } from '@nestjs/common';
import { TestService } from './test.service';
import { BaseController } from 'src/base/base.controller';
import { UpdateTestDto } from './dto/update-test.dto';

@Controller('test')
export class TestController extends BaseController<UpdateTestDto> {
  constructor(private readonly userService: TestService) {
    super(userService);
  }

  @Get("all")
  async findTest(): Promise<UpdateTestDto[]> {
    return await this.userService.findTest() as UpdateTestDto[];
  }
 
}

4.5、模块代码如下

注意必须导入TypeOrmModule.forFeature([Test])。

import { Module } from '@nestjs/common';
import { TestService } from './test.service';
import { Test } from './entities/test.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TestController } from './test.controller';

@Module({
  imports: [
    TypeOrmModule.forFeature([Test])
  ],
  controllers: [TestController],
  providers: [TestService],
})
export class TestModule {}

4.6、测试

在浏览器中输入http://localhost:8000/test,该接口会调用基类中的get方法。

image.png

在浏览器中输入http://localhost:8000/test/all

image.png