NestJS build blog system (10) – graph bed module

preface

Here do chart bed module mainly to save resources, at the same time convenient picture reuse. The basic function has the picture list and the picture adds, uploads the picture. In order to reuse resources, the image module needs to save the image path and MD5 value to calculate whether the image MD5 value exists when uploading the image.

Develop the chart bed module

nest g mo modules/picture nest g co modules/picture nest g s modules/picture

Entity DTO VO

// src/modules/picture/entity/picture.entity.ts

import { Common } from 'src/common/entity/common.entity';
import { Entity, Column } from 'typeorm';

@Entity(a)export class Picture extends Common{
  // Image path
  @Column('text')
  src: string;

  // File signature
  @Column('text')
  sign: string;
}
Copy the code
// src/modules/picture/dto/picture.dto.ts

import { IsNotEmpty } from "class-validator";
export class PictureDTO {

  /** * image path *@example /upload/static/1.png
   */
   @IsNotEmpty({ message: 'Please enter picture path' })
   readonly src: string;

}
Copy the code
// src/modules/picture/dto/picture-create.dto.ts

import { PictureDTO } from "./picture.dto";

export class PictureCreateDto extends PictureDTO {

   /** * md5 *@example asdfghjkl* /
    readonlysign? :string;
}
Copy the code
// src/modules/picture/vo/picture-info.dto.ts

import { SuccessVO } from "src/common/dto/success.dto";
import { PictureDTO } from ".. /dto/picture.dto";

export class PictureInfoItem extends PictureDTO{}

export class PictureInfoVO {
  info: PictureInfoItem
}

export class PictureInfoSuccessVO extends SuccessVO {
  data: {
    info: PictureInfoItem
  }
} 
Copy the code
// src/modules/picture/vo/picture-list.dto.ts

import { PaginationDTO } from "src/common/dto/pagination.dto";
import { SuccessVO } from "src/common/dto/success.dto";
import { PictureDTO } from ".. /dto/picture.dto";

export class PictureListItem extends PictureDTO {}

export class PictureListVO {
  list: PictureListItem[]
  pagination: PaginationDTO
}

export class PictureListSuccessVO extends SuccessVO {
  data: {
    list: PictureListItem[]
    pagination: PaginationDTO
  }
} 
Copy the code

Refer to the entity

// src/modules/picture/picture.modules.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Picture } from './entity/picture.entity';
import { PictureController } from './picture.controller';
import { PictureService } from './picture.service';

@Module({
  imports: [
    TypeOrmModule.forFeature([Picture]),
  ],
  controllers: [PictureController],
  providers: [PictureService]
})
export class PictureModule {}

Copy the code

The controller

import { Controller, Get, Post, Query, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { PageDTO } from 'src/common/dto/Page.dto';
import { PictureService } from './picture.service';
import { PictureInfoSuccessVO, PictureInfoVO } from './vo/picture-info.vo';
import { PictureListSuccessVO, PictureListVO } from './vo/picture-list.vo';

@ApiTags('Chart bed Module')
@Controller('picture')
export class PictureController {
  constructor(
    private pictureService: PictureService
  ) {}

  @ApiOkResponse({ description: 'Picture list'.type: PictureListSuccessVO })
  @Get('list')
  async getMany(
    @Query() pageDto: PageDTO
  ): Promise<PictureListVO> {
    return await this.pictureService.getMany(pageDto)
  }

  @ApiOkResponse({ description: 'Upload picture'.type: PictureInfoSuccessVO })
  @Post('upload')
  @UseInterceptors(FileInterceptor('file'))
  async upload(
    @UploadedFile() file:any) :Promise<PictureInfoVO> {
    console.log('controller', {file})
    return await this.pictureService.upload(file)
  }
}
Copy the code

Service

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { PageDTO } from 'src/common/dto/Page.dto';
import { getPagination } from 'src/utils/index.util';
import { Repository } from 'typeorm';
import { PictureCreateDto } from './dto/picture-create';
import { Picture } from './entity/picture.entity';
import { PictureInfoVO } from './vo/picture-info.vo';
import * as fs from 'fs';
import { encryptFileMD5 } from 'src/utils/cryptogram.util';
import { uploadStaticSrc } from 'src/config/upload/upload.config';

@Injectable(a)export class PictureService {
  constructor(
    @InjectRepository(Picture)
    private readonly pictureRepository: Repository<Picture>,
  ) {}

  async getMany(
    pageDto: PageDTO
  ) {
    const { page, pageSize } = pageDto
    const getList = this.pictureRepository
      .createQueryBuilder('picture')
      .select([
        'picture.src',
      ])
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount()

    const [list, total] = await getList
    const pagination = getPagination(total, pageSize, page)

    return {
      list,
      pagination,
    }
  }

  async create(
    pictureCreateDTO: PictureCreateDto
  ): Promise<PictureInfoVO> {
    const picture = new Picture()
    picture.src = pictureCreateDTO.src
    picture.sign = pictureCreateDTO.sign
    const result = await this.pictureRepository.save(picture)
    return {
      info: result
    }
  }

  async getOneBySign(sign: string) {
    return await this.pictureRepository
      .createQueryBuilder('picture')
      .where('picture.sign = :sign', { sign })
      .getOne()
  }

  async upload(file: any) {
    const { buffer } = file

    const currentSign = encryptFileMD5(buffer)
    const hasPicture = await this.getOneBySign(currentSign)

    if (hasPicture) {
      return {
        info: {
          src: hasPicture.src,
          isHas: true,}}}const arr = file.originalname.split('. ')
    const fileType = arr[arr.length - 1]
    const fileName = currentSign + '. ' + fileType
    fs.writeFileSync(`./upload/${fileName}`, buffer)

    const src = uploadStaticSrc + fileName

    this.create({ src, sign: currentSign })

    return {
      info: {
        src,
        isHas: false}}}}Copy the code

The static file path needs to be set

// src/config/upload/upload.config.ts

/ / static file path localhost/static/upload/XXX. JPG
export const uploadStaticSrc = '/static/upload/'
Copy the code
// src/main.ts

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './filters/http-exception.filter';
import { TransformInterceptor } from './interceptor/transform.interceptor';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { uploadStaticSrc } from './config/upload/upload.config';
import { join } from 'path';
import { NestExpressApplication } from '@nestjs/platform-express';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  app.useGlobalPipes(new ValidationPipe())
  app.useGlobalInterceptors(new TransformInterceptor())
  app.useGlobalFilters(new HttpExceptionFilter())

  app.useStaticAssets(join(__dirname, '.. '.'upload'), {
    prefix: uploadStaticSrc,
  });

  const options = new DocumentBuilder()
    .setTitle('blog-serve')
    .setDescription('Interface Document')
    .setVersion('1.0')
    .addBearerAuth()
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('swagger-doc', app, document);

  await app.listen(3000);
}
bootstrap();
Copy the code

At this point, the chart bed module with duplicate lookup function has been completed, although only the list view function and upload function, but enough to facilitate the reuse of resources

reference

  • NestJS
  • NestJS Chinese website
  • Code for this section

A series of

  • NestJS build blog system (a) – build a framework
  • NestJS build blog system (2) – write static article CURD
  • NestJS build blog system (3) – using TypeORM+Mysql to achieve data persistence
  • NestJS build blog system (four) – use interceptor, exception filter to achieve a unified return format
  • Use class-validator+ class validator to implement form validation
  • NestJS build blog system (6) – Use Swagger to generate documents
  • NestJS build blog system (7) – use JWT to register and log in
  • NestJS build blog system (eight) – project optimization
  • NestJS build blog system (nine) – tag module