nestjs + typeorm + mysql 实现用户权限管理应用 (二)

141 阅读2分钟

swagger 接入

安装相关依赖

npm install --save @nestjs/swagger swagger-ui-express

src/mian.js 文件中添加下面的代码

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'

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

  // swagger 
  const options = new DocumentBuilder()
    .setTitle('用户管理系统')
    .setDescription('用户、应用、角色、权限统一管理')
    .setVersion('1.0')
    // .addBearerAuth() // 添加 登录信息 
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('docs', app, document);

  await app.listen(3000);
}
bootstrap();

http://localhost:3000/docs

image.png

全局字段类验证器

安装相关依赖


npm i --save class-validator class-transformer

core/validate.pipe.ts 自定义验证

import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';

@Injectable()
export class ValidationPipe implements PipeTransform<any> {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToClass(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException('字段验证错误');
    }
    return value;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}

验证器使用. 于装饰器的验证

常见class- validators使用

import { ApiProperty } from '@nestjs/swagger';
import {
  IsNotEmpty,
  IsNumber,
  IsOptional,
  IsArray,
  IsEmail,
} from 'class-validator';

export class CreateUserDto {
  @ApiProperty()
  @IsNotEmpty()
  username: string;

  @ApiProperty()
  @IsNotEmpty()
  password: string;

  @ApiProperty()
  @IsNotEmpty()
  @IsEmail()
  email: string;

  @ApiProperty()
  roleIds: number[];

  @ApiProperty()
  @IsNotEmpty()
  display_name: string;

  @ApiProperty()
  @IsOptional()
  @IsArray({ each: true })
  appIds: number[];
}

export class SearchUserDto {
  @ApiProperty()
  @IsNotEmpty()
  @IsNumber()
  pageIndex: number;

  @ApiProperty()
  @IsNotEmpty()
  @IsNumber()
  pageSize: number;
}

export class UpdateUserDto extends CreateUserDto {
  @ApiProperty()
  @IsNotEmpty()
  @IsNumber()
  user_id: number;
}

export class UserResponse {
  user_id: number;
  username: string;
  email: string;
  display_name: string;
  appIds?: number[];
  roleIds?: number[];
}

全局使用配置

在 app.module.ts 文件中 加入provider

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';';
import { TypeOrmModule } from '@nestjs/typeorm';


import { APP_PIPE, APP_INTERCEPTOR } from '@nestjs/core';
import { ValidationPipe } from '../core/validate.pipe';

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      useFactory: async () => {
        return {
          type: 'mysql',
          host: 'localhost',
          database: 'user_system',
          port: 3306,
          username: 'root',
          password: 'root123456',
          synchronize: true, // 生产环境关闭
          autoLoadEntities: true,
        };
      },
    }),
  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_PIPE,
      useClass: ValidationPipe,
    },
  ],
})
export class AppModule {}


全局响应拦截器

统一数据返回结构

image.png

安装相关依赖

npm i --save rxjs

拦截器代码

import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class ResponseInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const message = this.getCustomMessage(context);

    return next.handle().pipe(
      map((data) => {
        // TODO: 数据类型为blob 需要处理
        return {
          code: 200,
          data,
          message,
        };
      }),
    );
  }

  private getCustomMessage(context: ExecutionContext): string {
    const httpContext = context.switchToHttp();
    const request = httpContext.getRequest();
    const url = request.url;

    let msg = '操作成功';

    if (url?.includes('/remove')) {
      msg = '删除成功';
    }
    if (url?.includes('/update')) {
      msg = '更新成功';
    }
    if (url?.includes('/create')) {
      msg = '新建成功';
    }

    return msg;
  }
}

全局使用

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';


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

import { APP_INTERCEPTOR } from '@nestjs/core';
import { ResponseInterceptor } from '../core/response.interceptor';


@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      useFactory: async () => {
        return {
          type: 'mysql',
          host: 'localhost',
          database: 'user_system',
          port: 3306,
          username: 'root',
          password: 'root123456',
          synchronize: true, // 生产环境关闭
          autoLoadEntities: true,
        };
      },
    }),

  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseInterceptor,
    },
  ],
})
export class AppModule {}


下一篇文章 用户登录功能加入。。。

相关文章

nestjs + typeorm + mysql 实现用户权限管理应用 (一)