nest进阶,swagger中间件管道守卫

341 阅读5分钟

nestJs笔记2

一 swagger文档

安装

yarn add @nestjs/swagger

引入

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

配置 main.ts

  // 设置swagger文档相关配置
  const swaggerOptions = new DocumentBuilder()
    .setTitle('nest api document')  //文档名
    .setDescription('nest api des') //文档描述
    .setVersion('1.0')  //版本
    .addBearerAuth()  //鉴权
    .build()
  // 创建文档
  const document = SwaggerModule.createDocument(app, swaggerOptions)
  SwaggerModule.setup('doc', app, document) //访问路径, 应用于, 文档

访问

localhost:3000/doc

nest集成swagger_大神乔伊的博客-CSDN博客_nest swagger

@ApiTags('user')   设置模块接口的分类,不设置默认分配到default
@ApiOperation({ summary: '标题', description: '详细描述'})  单个接口描述

传参
@ApiQuery({ name: 'limit', required: true})    query参数
@ApiQuery({ name: 'role', enum: UserRole })    query参数
@ApiParam({ name: 'id' })      parma参数
@ApiBody({ type: UserCreateDTO, description: '输入用户名和密码' })   请求体

响应
@ApiResponse({
    status: 200,
    description: '成功返回200,失败返回400',
    type: UserCreateDTO,
})

验证
@ApiProperty({ example: 'Kitty', description: 'The name of the Cat' })
name: string;

二 middleware logger

生成一个中间件

nest g middleware common/middleware/logging

在中间件函数内部进行操作

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express'

@Injectable()
export class LoggingMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: () => void) {
    // 我们在中间件函数内部可以拿到请求和响应的内容,根据这些内容可以做一些中间件操作
    // 默认req和res是any类型,需要引入express中的request和response
    console.log(req.method, req.params);
    next();
  }
}

应用中间件到路由

在module文件中,配置中间件的应用

import { MiddlewareConsumer, Module, NestMiddleware, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ArticalController } from './artical/artical.controller';
import { UsersController } from './users/users.controller';
import { EjsEngineController } from './ejs_engine/ejs_engine.controller';
import { NewsService } from './news/news.service';
import { NewsController } from './news/news.controller';
import { LoggingMiddleware } from './common/middleware/logging.middleware';

@Module({
  imports: [],
  // 在module中注册controller 和 providers
  controllers: [AppController, ArticalController, UsersController, EjsEngineController, NewsController],
  providers: [AppService, NewsService],
})
export class AppModule{
  // 配置middleware,将LoggingMiddleware应用于指定范围内的路由
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggingMiddleware)	//制定应用的中间件
      .exclude({path:'news', method:RequestMethod.POST})  //不应用于news路径下和POST请求的路由
      .forRoutes('*')
  }
}

三 异常处理

四 管道

管道用于转换参数类型

在方法参数装饰器内调用类(局部管道)

转换前

    @Get('getUserBy')
    getUserBy(@Query('id') id): String {
        console.log(id);    //123
        console.log(typeof(id));	//String
        return '获取用户'
    }

转换后

    @Get('getUserBy')
    getUserBy(@Query('id', new ParseIntPipe()) id:number): String {
        console.log(id);    //123
        console.log(typeof(id));	//number
        return '获取用户'
    }

创建管道pipe

nest g pipe pipes/parse-int

五 守卫

守卫在中间件之后执行,但是在管道和拦截器之前执行

创建守卫

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
  // guard内必须要有一个函数canActive
  canActivate(
    context: ExecutionContext, // canActive内唯一参数context是ExecutionContext实例
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    console.log('request',request)
    return true;
  }
}

使用守卫

// 全局使用守卫
 app.useGlobalGuards(new RoleGuardGuard())

// 局部使用守卫(作为装饰器使用)
import { Body, Controller, Get, Param, ParseIntPipe, Post, Query, Request, UseGuards } from '@nestjs/common';
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import { AuthGuard } from 'src/common/guard/role-guard.guard';

@UseGuards(AuthGuard)	//请求use下接口会被gaurd调用
@Controller('users')
@ApiTags('user')
export class UsersController {
    @Get()
    index(): String{
        return '用户中心'
    }
}

六 数据库连接

可以直接使用任何通用的nodejs数据库集成库或ORM例如 Sequelize (recipe)knexjs (tutorial)`和 TypeORM ,以在更高的抽象级别上进行操作。

这里使用Sequelize来对数据库操作,相较于官网推荐的TypeORM更加稳定,npm下载量也更高

安装

安装数据库驱动程序和sequelize
yarn add @nestjs/sequelize sequelize sequelize-typescript mysql2
安装对ts的支持
yarn add @types/sequelize --dev

步骤:

1 导入sequelize模块 app.module.ts

import { MiddlewareConsumer, Module, NestMiddleware, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ArticalController } from './artical/artical.controller';
import { UsersController } from './users/users.controller';
import { EjsEngineController } from './ejs_engine/ejs_engine.controller';
import { NewsService } from './news/news.service';
import { NewsController } from './news/news.controller';
import { LoggingMiddleware } from './common/middleware/logging.middleware';
import { SequelizeModule } from '@nestjs/sequelize';
import { SongListModule } from './song_list/song_list.module';
import { Song_list } from './song_list/song_list.model';

@Module({
  imports: [
    // 配置连接数据库信息
    SequelizeModule.forRoot({
      dialect: 'mysql',
      host: 'localhost',
      port: 3309,
      username: 'root',
      password: '123456',
      database: 'graduation_project',
      models: [Song_list], //引入表格模型
    }),
    SongListModule
  ],
  // 在module中注册controller 和 providers
  controllers: [AppController, ArticalController, UsersController, EjsEngineController, NewsController],
  providers: [AppService, NewsService],
})
export class AppModule{
  // 配置middleware,将LoggingMiddleware应用于指定范围内的路由
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggingMiddleware)
      .exclude({path:'news', method:RequestMethod.POST})  //不应用于news路径下和POST请求的路由
      .forRoutes('*')
  }
}

2 注入Sequelize到项目中 app.service.ts

import { Injectable } from '@nestjs/common';
import { Sequelize } from 'sequelize-typescript';

@Injectable()
export class AppService {
  // 注入Sequelize到项目中
  constructor(private sequelize: Sequelize) { }
  getHello(): string {
    return 'nihao1 nestjs';
  }

  getp(): String {
    return 'product'
  }
}

3 定义一个模型 song_list.model.ts

// 在model文件内创建表格模型 可以通过@Column({defaultValue: true})
import { Table, Column, Model } from "sequelize-typescript";
@Table
export class Song_list extends Model<Song_list>{
    @Column({primaryKey: true})
    id: number
    @Column
    listname: String
    @Column
    collect: number
    @Column
    share: number
    @Column
    comment: number
}

4 要开始使用模型,我们需要通过将其插入到forRoot()方法选项的models数组中来让Sequelize知道它的存在。

//app.modules.ts 
imports: [
    // 配置连接数据库信息
    SequelizeModule.forRoot({
      dialect: 'mysql',
      host: 'localhost',
      port: 3309,
      username: 'root',
      password: '123456',
      database: 'graduation_project',
      models: [Song_list], //引入表格模型
      //配置防止报错
      define: {
        freezeTableName: true,  //配置不在表名后面加s
        timestamps: false //配置不加createdAt和updateAt字段
      }
    }),
    SongListModule	//导入模块
  ],

5 在service内注入表格模型,对该表进行增删改查功能 song_list.service.ts

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { Song_list } from './song_list.model';

@Injectable()
export class SongListService {
    constructor(
        //使用@InjectModel()装饰器来把UserModel注入到UsersService中。
        @InjectModel(Song_list)
        private songListModel: typeof Song_list
    ) { }
    //查找所有数据
    async findAll(): Promise<Song_list[]> {
        return this.songListModel.findAll();
    }
}

6 使用service内的功能,开放数据接口 song_list.controller.ts

import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { SongListService } from './song_list.service';

@Controller('songlist')
    @ApiTags('songlist')
export class SongListController {
    constructor(private SongListService: SongListService) { }

    @Get('allsong')
    getAllSong() {
        return this.SongListService.findAll()
    }

    @Get()
    getData() {
        return 'song list print msg'
    }
}

7 将模块注册导出 song_list.module.ts

import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { Song_list } from './song_list.model';
import { SongListController } from './song_list.controller';
import { SongListService } from './song_list.service';


@Module({
    imports: [SequelizeModule.forFeature([Song_list])],//定义songListModule模块被注册到当前范围内
    controllers: [SongListController],	
    providers: [SongListService],
    exports: [SequelizeModule]	//导出Sequelize
})
export class SongListModule {}

七 jwt验证登录

本地passport策略

yarn add @nestjs/passport passport passport-local
yarn add @types/passport-local -D

安装依赖

yarn add @nestjs/jwt passport-jwt
yarn add @types/passport-jwt -D