【前端】Nesj 学习笔记

1、前置知识

1.1 装饰器

装饰器的类型

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => void;

1.2 实现一个get请求装饰器

import axios from "axios";const getDecorator = (url: string) => {return function (target: Object,propertyKey: string | symbol,descriptor: any) {axios.get(url).then((res) => {descriptor.value(res, { state: "1" });}).catch((err) => {descriptor.value(err, { state: "0" });});};
};class AxiosDecorator {name: string;constructor() {this.name = "你好 啊";}@getDecorator("https://jsonplaceholder.typicode.com/posts")axiosGet(res: any, state: any) {console.log(res, state);}
}

2、nest cli 创建项目

npm i -g @nestjs/clinest new [项目名称]
//创建完成后,目录结果如下
src├── app.controller.spec.ts├── app.controller.ts├── app.module.ts├── app.service.ts└── main.ts
app.controller.ts带有单个路由的基本控制器示例。
app.controller.spec.ts对于基本控制器的单元测试样例
app.module.ts应用程序的根模块。
app.service.ts带有单个方法的基本服务
main.ts应用程序入口文件。它使用 NestFactory 用来创建 Nest 应用实例。
  "scripts": {"build": "nest build","format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","start": "nest start","start:dev": "nest start --watch","start:debug": "nest start --debug --watch","start:prod": "node dist/main","lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix","test": "jest","test:watch": "jest --watch","test:cov": "jest --coverage","test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand","test:e2e": "jest --config ./test/jest-e2e.json"},

一般的话用 npm run start:dev

3、nest cli 常用命令

在这里插入图片描述

nest g resource xxx 可以直接生成一套模板

在这里插入图片描述

4、nest 控制器

@Request(),@Req()req
@Response(),@Res()res
@Next()next
@Session()req.session
@Param(key?: string)req.params/req.params[key]
@Body(key?: string)req.body/req.body[key]
@Query(key?: string)req.query/req.query[key]
@Headers(name?: string)req.headers/req.headers[name]
@Ip()req.ip
@HostParam()req.hosts
import {Controller,Get,Post,Body,Patch,Param,Delete,Version,Request,Query,
} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { version } from 'process';
// import { Request } from 'express';// 给这个模块全局增加版本号// @Controller({
//   path: 'user',
//   version: '1',
// })
@Controller('user')
export class UserController {constructor(private readonly userService: UserService) {}// 查询参数是 @Request 装饰器的  query// 如果放在body 里面了  是 @Request 装饰的 body@Get()findAll(@Request() req) {// 也可以直接使用Query 装饰器,就不用 .query了// console.log(req);console.log(req.query);return {state: '1',data: req.query,};}@Post()create(@Request() req) {// 也有 @Body 装饰器// body 如果有多个参数,只想读取某一个东西,还可以直接写 @Body('xxx') ,query 同理console.log('post请求', req.body);return {state: '1',data: req.body,};}@Get(':id')selectByID(@Request() req) {// 也有 @Param 装饰器return {state: '1',data: req.params,};}@Get('select')select() {return {state: '1',data: 'select',};}// @Post()// create(@Body() createUserDto: CreateUserDto) {//   return this.userService.create(createUserDto);// }// // 也可以单独添加版本// @Get()// @Version('1')// findAll() {//   return this.userService.findAll();// }// @Get(':id')// findOne(@Param('id') id: string) {//   return this.userService.findOne(+id);// }// @Patch(':id')// update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {//   return this.userService.update(+id, updateUserDto);// }// @Delete(':id')// remove(@Param('id') id: string) {//   return this.userService.remove(+id);// }
}

5、providers

5.1 基本用法

在这里插入图片描述

在这里插入图片描述

控制器里面的方法就能用这个 userservice 里面的方法了

5.2 service 第二种用法,自定义名称

  1. 修改user.module.ts
  2. 修改 user.controller.ts
// user.module.ts
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';@Module({controllers: [UserController],// providers: [UserService], // 这个是简写providers: [{provide: 'ddgService',useClass: UserService,},],
})
export class UserModule {}
import {Controller,Get,Post,Body,Patch,Param,Delete,Version,Request,Query,Inject,
} from '@nestjs/common';
import { UserService } from './user.service';@Controller('user')
export class UserController {// constructor(private readonly userService: UserService) {}// 如果自定义了 服务的名称,这里需要把名称传递进来constructor(@Inject('ddgService') private readonly userService: UserService,) {}
}

5.3 自定义注入值

可以通过 providers 数组的 useValue 自定义注入值

import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';@Module({controllers: [UserController],// providers: [UserService], // 这个是简写providers: [{provide: 'ddgService',useClass: UserService,},{provide: 'ddgService2',useValue: ['呆呆狗1号', '呆呆狗2号', '呆呆狗3号'],},],
})
export class UserModule {}
import {Controller,Get,Post,Body,Patch,Param,Delete,Version,Request,Query,Inject,
} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { version } from 'process';@Controller('user')
export class UserController {constructor(@Inject('ddgService') private readonly userService: UserService,@Inject('ddgService2') private ddgName: string[],) {}@Get()findAll(@Request() req) {// 也可以直接使用Query 装饰器,就不用 .query了// console.log(req);console.log(req.query);console.log('providers 的 ddgService2的值', this.ddgName);return {state: '1',data: req.query,};}
}

在这里插入图片描述

5.4 工厂模式

在这里插入图片描述

// user.service2
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';@Injectable()
export class UserService2 {getSay() {return '你好啊,我是工厂模式下注入的';}
}
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserService2 } from './user.service2';
import { UserController } from './user.controller';@Module({controllers: [UserController],// providers: [UserService], // 这个是简写providers: [{provide: 'ddgService',useClass: UserService,},{provide: 'ddgService2',useValue: ['呆呆狗1号', '呆呆狗2号', '呆呆狗3号'],},UserService2,{provide: 'ddgService3',inject: [UserService2],useFactory: (UserService2: UserService2) => {console.log(UserService2.getSay());// 这里也可以使用  async await  ,异步模式也可以return 123;},},],
})
export class UserModule {}
import {Controller,Get,Post,Body,Patch,Param,Delete,Version,Request,Query,Inject,
} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { version } from 'process';@Controller('user')
export class UserController {constructor(@Inject('ddgService') private readonly userService: UserService,@Inject('ddgService2') private ddgName: string[],@Inject('ddgService3') private getSay: number,) {}@Get()findAll(@Request() req) {// 也可以直接使用Query 装饰器,就不用 .query了// console.log(req);console.log(req.query);console.log('providers 的 ddgService2的值', this.ddgName);console.log(this.getSay);return {state: '1',data: req.query,};}
}

在这里插入图片描述

6、模块

每个 Nest 应用程序至少有一个模块,即根模块。根模块是 Nest 开始安排应用程序树的地方。事实上,根模块可能是应用程序中唯一的模块,特别是当应用程序很小时,但是对于大型程序来说这是没有意义的。在大多数情况下,您将拥有多个模块,每个模块都有一组紧密相关的功能

6.1 共享模块

例如 想让 app 模块 访问 user模块的service

1、定义一个函数

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';@Injectable()
export class UserService2 {getSay() {return '你好啊,我是工厂模式下注入的';}getLook() {  //  一会要调用的函数return '我是user 模块的 service';}
}

2、在 user模块里面 导出 这个服务

在这里插入图片描述

import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserService2 } from './user.service2';
import { UserController } from './user.controller';@Module({controllers: [UserController],// providers: [UserService], // 这个是简写providers: [{provide: 'ddgService',useClass: UserService,},{provide: 'ddgService2',useValue: ['呆呆狗1号', '呆呆狗2号', '呆呆狗3号'],},UserService2,{provide: 'ddgService3',inject: [UserService2],useFactory: (UserService2: UserService2) => {console.log(UserService2.getSay());return 123;},},],exports: [UserService2],
})
export class UserModule {}

3、在 app控制器里面引入以下 user的service 然后 注入以下,直接调用函数即可

在这里插入图片描述

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { UserService2 } from './user/user.service2';// @Controller()
@Controller('get') // 相当于 路由前缀
export class AppController {constructor(private readonly appService: AppService,private readonly UserService2: UserService2,) {}// @Get()@Get('hello') //路由地址getHello(): string {// 使用 user 模块的 servicelet abc = this.UserService2.getLook();console.log(abc);return this.appService.getHello();}
}

6.2 全局模块

1、先创建一个 config 模块

import { Global, Module } from '@nestjs/common';@Global() // 定义为全局模块
@Module({providers: [{provide: 'config',useValue: {baseUrl: 'http:www.baidu.com',},},],// 全局模块也要导出一遍exports: [{provide: 'config',useValue: {baseUrl: 'http:www.baidu.com',},},],
})
export class ConfigModule {}

2、在 app模块 中,导入这个 config 模块

在这里插入图片描述

3、在任何一个控制器中使用, 使用方法类似于5.2 章节

import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
import { UserService2 } from './user/user.service2';// @Controller()
@Controller('get') // 相当于 路由前缀
export class AppController {constructor(private readonly appService: AppService,private readonly UserService2: UserService2,@Inject('config') private readonly config: any,) {}// @Get()@Get('hello') //路由地址getHello(): string {// 使用 user 模块的 servicelet abc = this.UserService2.getLook();console.log(abc);console.log('全局模块的注入', this.config);return this.appService.getHello();}
}

6.3 动态模块

1、增加一个静态方法

// config.module.ts
import { Module, DynamicModule, Global } from '@nestjs/common';interface Options {path: string;
}@Global()
@Module({})
export class ConfigModule {static forRoot(options: Options): DynamicModule {return {module: ConfigModule,providers: [{provide: 'config',useValue: { baseApi: 'http:www.baidu.com' + options.path },},],exports: [{provide: 'config',useValue: { baseApi: 'http:www.baidu.com' + options.path },},],};}
}

2、修改 imports 导入的全局模块

// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DemoController } from './demo/demo.controller';
import { DemoModule } from './demo/demo.module';
import { UserModule } from './user/user.module';
import { ListModule } from './list/list.module';
import { ConfigModule } from './config/config.module';@Module({// imports: [DemoModule, UserModule, ListModule, ConfigModule],imports: [DemoModule,UserModule,ListModule,ConfigModule.forRoot({path: '/ddg',}),],controllers: [AppController, DemoController],providers: [AppService],
})
export class AppModule {}

7、中间件

中间件是在路由处理程序 之前 调用的函数。 中间件函数可以访问请求和响应对象

中间件函数可以执行以下任务:

  • 执行任何代码。
  • 对请求和响应对象进行更改。
  • 结束请求-响应周期。
  • 调用堆栈中的下一个中间件函数。
  • 如果当前的中间件函数没有结束请求-响应周期, 它必须调用 next() 将控制传递给下一个中间件函数。否则, 请求将被挂起。

执行顺序是 先全局中间件 => 局部中间件

布局中间件需要类,全局直接一个函数即可

7.1 局部中间件

 nest g mi logger // 生成一个 中间件
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {use(req: Request, res: Response, next: NextFunction) {console.log('路由拦截器嘿嘿嘿,我是局部中间件');// res.send('拦截你');next();}
}
import {Logger,MiddlewareConsumer,Module,NestModule,RequestMethod,
} from '@nestjs/common';
import { UserService } from './user.service';
import { UserService2 } from './user.service2';
import { UserController } from './user.controller';
import { LoggerMiddleware } from 'src/logger/logger.middleware';@Module({controllers: [UserController],// providers: [UserService], // 这个是简写providers: [{provide: 'ddgService',useClass: UserService,},{provide: 'ddgService2',useValue: ['呆呆狗1号', '呆呆狗2号', '呆呆狗3号'],},UserService2,{provide: 'ddgService3',inject: [UserService2],useFactory: (UserService2: UserService2) => {console.log(UserService2.getSay());return 123;},},],exports: [UserService2],
})// export class UserModule {}
export class UserModule implements NestModule {configure(consumer: MiddlewareConsumer) {// 拦截这个控制器的接口// consumer.apply(LoggerMiddleware).forRoutes('user');// 拦截这个控制器下的 指定 格式的接口consumer.apply(LoggerMiddleware).forRoutes({method: RequestMethod.GET,path: '/user',});// 拦截所有的// consumer.apply(LoggerMiddleware).forRoutes(UserController);}
}

user,module 使用中间件

7.2 全局中间件

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { VersioningType } from '@nestjs/common';function middleWareAll(req, res, next) {console.log('我是全局中间件');next();
}async function bootstrap() {const app = await NestFactory.create(AppModule);// 注册全局中间件app.use(middleWareAll);app.enableCors(); // 跨域的// 处理接口版本// 然后再控制器里面 开启版本号app.enableVersioning({type: VersioningType.URI,});await app.listen(3000);
}
bootstrap();

8、上传图片及资源目录

# 安装这俩包
multer   @types/multer

新建一个 upload 模块

修改modules

import { Module } from '@nestjs/common';
import { UploadService } from './upload.service';
import { UploadController } from './upload.controller';
import { MulterModule } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { join, extname } from 'path';@Module({imports: [MulterModule.register({// 配置图片存放的位置storage: diskStorage({destination: join(__dirname, '../images'),filename: (req, file, cb) => {console.log('文件信息', file);const filename = `${Date.now()}-${extname(file.originalname)}`;return cb(null, filename);},}),}),],controllers: [UploadController],providers: [UploadService],
})
export class UploadModule {}

修改controller

import {Controller,Post,UploadedFile,UseInterceptors,
} from '@nestjs/common';
import { UploadService } from './upload.service';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';@Controller('upload')
export class UploadController {constructor(private readonly uploadService: UploadService) {}@Post()// 单个文件就是 FileInterceptor,参数就是 对象的key// 多个文件就是,FilesInterceptor, 区别就是file是后面有没有s@UseInterceptors(FileInterceptor('file'))upload(@UploadedFile() file) {return {state: '1',data: {file,},};}
}

开启资源目录

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { VersioningType } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';function middleWareAll(req, res, next) {console.log('我是全局中间件');next();
}async function bootstrap() {const app = await NestFactory.create<NestExpressApplication>(AppModule);// 注册全局中间件app.use(middleWareAll);app.enableCors(); // 跨域的// 处理接口版本// 然后再控制器里面 开启版本号app.enableVersioning({type: VersioningType.URI,});// 配置静态资源访问目录app.useStaticAssets(join(__dirname, 'images'), {prefix: '/file',});await app.listen(3000);
}
bootstrap();

9、下载图片

10、拦截器

在公司的后端接口,都是标准格式的,比如下图。一般都是有一个标准的json格式

在这里插入图片描述

在src 下,创建 utils 文件夹,然后创建 responseIntercept.ts 文件

// src/utils/responseIntercept.tsimport {Injectable,NestInterceptor,CallHandler,ExecutionContext,
} from '@nestjs/common';
import { map } from 'rxjs/operators';
import type { Observable } from 'rxjs';interface data<T> {data: T;
}@Injectable()
export class ResponseIntercept<T = any> implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler): Observable<data<T>> {return next.handle().pipe(map((data) => {return {data, // 这里的data 就是控制器,return的东西state: '1',mssage: 'hello 呆呆狗',};}),);}
}

然后在 main.ts 里面引入

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { VersioningType } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { ResponseIntercept } from './utils/responseIntercept';function middleWareAll(req, res, next) {console.log('我是全局中间件');next();
}async function bootstrap() {const app = await NestFactory.create<NestExpressApplication>(AppModule);// 注册全局中间件app.use(middleWareAll);app.enableCors(); // 跨域的// 处理接口版本// 然后再控制器里面 开启版本号app.enableVersioning({type: VersioningType.URI,});// 配置静态资源访问目录app.useStaticAssets(join(__dirname, 'images'), {prefix: '/file',});// 注册全局 请求响应拦截器app.useGlobalInterceptors(new ResponseIntercept());await app.listen(3000);
}
bootstrap();

11、异常拦截器

在 src / utils 文件夹下,创建 errorIntercept.ts 文件

// src/utils/errorIntercept.ts
import {ExceptionFilter,Catch,ArgumentsHost,HttpException,
} from '@nestjs/common';import type { Request, Response } from 'express';@Catch(HttpException)
export class HttpFilter implements ExceptionFilter {catch(exception: HttpException, host: ArgumentsHost) {const ctx = host.switchToHttp();const request = ctx.getRequest<Request>();const response = ctx.getResponse<Response>();const status = exception.getStatus();// console.log('status', status, request., response);response.status(status).json({data: exception.message,time: new Date().getTime(),success: false,path: request.url,status,});}
}
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { VersioningType } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { ResponseIntercept } from './utils/responseIntercept';
import { HttpFilter } from './utils/errorIntercept';function middleWareAll(req, res, next) {console.log('我是全局中间件');next();
}async function bootstrap() {const app = await NestFactory.create<NestExpressApplication>(AppModule);// 注册全局中间件app.use(middleWareAll);app.enableCors(); // 跨域的// 处理接口版本// 然后再控制器里面 开启版本号app.enableVersioning({type: VersioningType.URI,});// 配置静态资源访问目录app.useStaticAssets(join(__dirname, 'images'), {prefix: '/file',});// 全局 异常拦截器app.useGlobalFilters(new HttpFilter());// 注册全局 请求响应拦截器app.useGlobalInterceptors(new ResponseIntercept());await app.listen(3000);
}
bootstrap();

当 访问一个不存在的路由的时候 ,就会报以下错误

在这里插入图片描述

12、内置管道

在这里插入图片描述

Nest 自带九个开箱即用的管道,即

  • ValidationPipe
  • ParseIntPipe
  • ParseFloatPipe
  • ParseBoolPipe
  • ParseArrayPipe
  • ParseUUIDPipe
  • ParseEnumPipe
  • DefaultValuePipe
  • ParseFilePipe

他们从 @nestjs/common 包中导出。

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

如若请求,http://127.0.0.1:3000/list/2 ,接口返回值

{"data": "Validation failed (uuid is expected)","time": 1718319105042,"success": false,"path": "/list/2","status": 400
}

因为他需要一个guid

13、管道验证

先生成一个模块 nest g res pipeValidate

就会在 src 文件夹下看到以下目录

在这里插入图片描述

然后再这个文件夹下,生成一个 验证管道 nest g pi validate

在这里插入图片描述

// ./validate/validate.pipe
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';@Injectable()
export class ValidatePipe implements PipeTransform {transform(value: any, metadata: ArgumentMetadata) {console.log('管道验证', value, metadata);return value;}
}

然后对 控制器文件的 某个接口,增加管道验证

需要先导入 ./validate/validate.pipe ,然后 传递给某个接口的,

import {Controller,Get,Post,Body,Patch,Param,Delete,
} from '@nestjs/common';
import { PipeValidateService } from './pipe-validate.service';
import { CreatePipeValidateDto } from './dto/create-pipe-validate.dto';
import { UpdatePipeValidateDto } from './dto/update-pipe-validate.dto';// 管道验证
import { ValidatePipe } from './validate/validate.pipe';@Controller('pipe-validate')
export class PipeValidateController {constructor(private readonly pipeValidateService: PipeValidateService) {}@Post()// create(@Body() createPipeValidateDto: CreatePipeValidateDto) {//   return this.pipeValidateService.create(createPipeValidateDto);// }create(@Body(ValidatePipe) createPipeValidateDto: CreatePipeValidateDto) {return this.pipeValidateService.create(createPipeValidateDto);}
}

用在 body 后,测试一下这个接口,接口传递

{

“name”:“呆呆狗”,

“age”: 20

}

然后 验证器的ts文件, 打印 console.log(‘管道验证’, value, metadata); 结果如下

管道验证 { name: '呆呆狗', age: 20 } {metatype: [class CreatePipeValidateDto],type: 'body',data: undefined
}

value 就是 控制器里面解析的body的值, metadata 就是这个 类, type 是 控制器里面,用 这个管道验证,前面装饰器的名称。 data 就是 装饰器的 key 名称

控制器如若改成 @Body(‘name’, ValidatePipe) 那么输出就是以下结果

管道验证 呆呆狗 { metatype: [class CreatePipeValidateDto], type: 'body', data: 'name' }

安装验证器

npm i --save class-validator class-transformer

修改验证器 metadata的 metatype 的class 对应的文件,就是 dto/create-pipe-validate.dto.ts

// dto/create-pipe-validate.dto.ts
import { IsNotEmpty, IsString, Length, IsNumber } from 'class-validator';
export class CreatePipeValidateDto {@IsNotEmpty() //验证是否为空@IsString() //是否为字符串@Length(3, 10, {message: 'name的长度在3到10之间',})name: string;@IsNotEmpty()@IsNumber()age: number;
}

在这里插入图片描述

// validate.pipe.ts
import {ArgumentMetadata,HttpException,HttpStatus,Injectable,PipeTransform,
} from '@nestjs/common';import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';@Injectable()
export class ValidatePipe implements PipeTransform {async transform(value: any, metadata: ArgumentMetadata) {// console.log('管道验证', value, metadata);const dto = plainToInstance(metadata.metatype, value);const errors = await validate(dto);console.log('errors', errors);if (errors.length) {throw new HttpException(errors, HttpStatus.BAD_REQUEST);}return value;}
}// 如若 前端传递参数是  { "name":'呆呆',"age":"" } ,则有以下报错// errors [
//   ValidationError {
//     target: CreatePipeValidateDto { name: '呆呆', age: '' },
//     value: '呆呆',
//     property: 'name',
//     children: [],
//     constraints: { isLength: 'name的长度在3到10之间' }
//   },
//   ValidationError {
//     target: CreatePipeValidateDto { name: '呆呆', age: '' },
//     value: '',
//     property: 'age',
//     children: [],
//     constraints: { isNotEmpty: 'age should not be empty' }
//   }
// ]// 其实就是 返回一个数组,数组每一项的类型是 ValidationError

因为前面加了异常拦截器,所以会按照一定格式输出 。但是要把这里修改以下

在这里插入图片描述

全局 管道验证

在这里插入图片描述

这里换一下

修改 main.ts

// 增加以下代码
import { ValidationPipe } from '@nestjs/common';// 注册全局 管道验证app.useGlobalPipes(new ValidationPipe());

全局拦截器输出示例

{"data": {"response": {"message": ["name的长度在3到10之间","age must be a number conforming to the specified constraints"],"error": "Bad Request","statusCode": 400},"status": 400,"options": {},"message": "Bad Request Exception","name": "BadRequestException"},"time": 1718492535054,"success": false,"path": "/pipe-validate/","status": 400
}

14、爬虫

  • cheerio: 是jquery核心功能的一个快速灵活而又简洁的实现,主要是为了用在服务器端需要对DOM进行操作的地方,让你在服务器端和html愉快的玩耍。
  • axios 网络请求库可以发送http请求

15、守卫(guard)

守卫有一个单独的责任。它们根据运行时出现的某些条件(例如权限,角色,访问控制列表等)来确定给定的请求是否由路由处理程序处理。这通常称为授权。在传统的 Express 应用程序中,通常由中间件处理授权(以及认证)。中间件是身份验证的良好选择,因为诸如 token 验证或添加属性到 request 对象上与特定路由(及其元数据)没有强关联。

守卫在每个中间件之后执行,但在任何拦截器或管道之前执行

先创建一个模块

nest g res guard# 然后创建 模块的守卫
nest g gu [name]

在这里插入图片描述

全局路由守卫的使用方式

// main.ts 文件
import { RoleGuard } from './guard/role/role.guard';// 全局路由守卫app.useGlobalGuards(new RoleGuard());

局部路由守卫的使用方式

// guard.controller.ts 文件
import {Controller,Get,Post,Body,Patch,Param,Delete,UseGuards,
} from '@nestjs/common';
import { GuardService } from './guard.service';
import { CreateGuardDto } from './dto/create-guard.dto';
import { UpdateGuardDto } from './dto/update-guard.dto';
import { RoleGuard } from './role/role.guard';@Controller('guard')
export class GuardController {constructor(private readonly guardService: GuardService) {}@Get()@UseGuards(RoleGuard)findAll() {return this.guardService.findAll();}}

先用 局部的继续往下

import {Controller,Get,Post,Body,Patch,Param,Delete,UseGuards,SetMetadata,
} from '@nestjs/common';
import { GuardService } from './guard.service';
import { CreateGuardDto } from './dto/create-guard.dto';
import { UpdateGuardDto } from './dto/update-guard.dto';
import { RoleGuard } from './role/role.guard';@Controller('guard')
export class GuardController {constructor(private readonly guardService: GuardService) {}// 加以下 这个信息,@Get()@UseGuards(RoleGuard)@SetMetadata('role', ['admin'])findAll() {return this.guardService.findAll();}}
// role.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';import type { Request } from 'express';@Injectable()
export class RoleGuard implements CanActivate {constructor(private Reflector: Reflector) {}canActivate(context: ExecutionContext,): boolean | Promise<boolean> | Observable<boolean> {const admin = this.Reflector.get<string[]>('role', context.getHandler());const request = context.switchToHttp().getRequest<Request>();if (admin.includes(request.query.role as string)) {return true;} else {return false;}}
}

没有权限的话就直接触发,全局异常拦截器

在这里插入图片描述

在这里插入图片描述

16、自定义装饰器

nest.js 是可以自定义装饰器

在这里插入图片描述

nest g d [name]

自定义权限装饰器

// role.decorator.ts
import { SetMetadata } from '@nestjs/common';export const Role = (...args: string[]) => SetMetadata('role', args);
  @Get()@UseGuards(RoleGuard)// @SetMetadata('role', ['admin'])@Role('admin')findAll() {return this.guardService.findAll();}

自定义参数装饰器

import { SetMetadata,createParamDecorator,ExecutionContext ,applyDecorators } from '@nestjs/common';
import type {Request} from 'express'export const ReqUrl = createParamDecorator((data:string,ctx:ExecutionContext)=>{const req = ctx.switchToHttp().getRequest<Request>()return req.url
})
  @Get()@UseGuards(RoleGuard)// @SetMetadata('role', ['admin'])@Role('admin')findAll(@ReqUrl('123') url) {console.log('url', url, '自定义参数装饰器读取到的');return this.guardService.findAll();}

17、nestjs链接数据库(typeOrm)

npm install --save @nestjs/typeorm typeorm mysql2
  1. 修改app.module.ts 文件

主要是要引入 typeorm ,然后配置数据库的连接串及其他信息

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DemoController } from './demo/demo.controller';
import { DemoModule } from './demo/demo.module';
import { UserModule } from './user/user.module';
import { ListModule } from './list/list.module';
import { ConfigModule } from './config/config.module';
import { UploadModule } from './upload/upload.module';
import { PipeValidateModule } from './pipe-validate/pipe-validate.module';
import { GuardModule } from './guard/guard.module';
import { TestdatabaseModule } from './testdatabase/testdatabase.module';// 引入 typeorm
import { TypeOrmModule } from '@nestjs/typeorm';@Module({// imports: [DemoModule, UserModule, ListModule, ConfigModule],imports: [DemoModule,UserModule,ListModule,ConfigModule.forRoot({path: '/ddg',}),UploadModule,PipeValidateModule,GuardModule,TestdatabaseModule,TypeOrmModule.forRoot({type: 'mysql', //数据库类型username: 'root', //账号password: '123456', //密码host: 'localhost', //hostport: 3306, //database: 'spe', //库名entities: [__dirname + '/**/*.entity{.ts,.js}'], //实体文件synchronize: true, //synchronize字段代表是否自动将实体类同步到数据库retryDelay: 500, //重试连接数据库间隔retryAttempts: 10, //重试连接数据库的次数autoLoadEntities: true, //如果为true,将自动加载实体 forFeature()方法注册的每个实体都将自动添加到配置对象的实体数组中}),],controllers: [AppController, DemoController],providers: [AppService],
})
export class AppModule {}
  1. 用 nest g res testdatabase 创建模块

  2. 修改实体文件 entities/testdatabase.entity.ts

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';@Entity()
export class test {// test 就是表名称@PrimaryGeneratedColumn()id: number;@Column()name: string;@Column()password: string;
}
  1. 修改 testdatabase.module.ts 导入这个实体
import { Module } from '@nestjs/common';
import { TestdatabaseService } from './testdatabase.service';
import { TestdatabaseController } from './testdatabase.controller';import { test } from './entities/testdatabase.entity';
import { TypeOrmModule } from '@nestjs/typeorm';@Module({imports: [TypeOrmModule.forFeature([test])],controllers: [TestdatabaseController],providers: [TestdatabaseService],
})
export class TestdatabaseModule {}

这样重新运行以下,就会创建 test 表

在这里插入图片描述

18、curd

实现创建 用户

  1. 修改testdatabase.service.js
import { Injectable } from '@nestjs/common';
import { CreateTestdatabaseDto } from './dto/create-testdatabase.dto';
import { UpdateTestdatabaseDto } from './dto/update-testdatabase.dto';
import { InjectRepository } from '@nestjs/typeorm';import { test as User } from './entities/testdatabase.entity';
import { Repository } from 'typeorm';@Injectable()
export class TestdatabaseService {constructor(@InjectRepository(User) private readonly userRecord: Repository<User>,) {}async create(createTestdatabaseDto) {const userRecord = new User();userRecord.name = createTestdatabaseDto.name;userRecord.password = createTestdatabaseDto.password;return await this.userRecord.save(userRecord);}findAll() {return `This action returns all testdatabase`;}findOne(id: number) {return `This action returns a #${id} testdatabase`;}update(id: number, updateTestdatabaseDto: UpdateTestdatabaseDto) {return `This action updates a #${id} testdatabase`;}remove(id: number) {return `This action removes a #${id} testdatabase`;}
}

在这里插入图片描述

这样刷新以下表,就可以看到了

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/29030.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GenICam标准(三)

系列文章目录 GenICam标准&#xff08;一&#xff09; GenICam标准&#xff08;二&#xff09; GenICam标准&#xff08;三&#xff09; GenICam标准&#xff08;四&#xff09; GenICam标准&#xff08;五&#xff09; GenICam标准&#xff08;六&#xff09; 文章目录 系列文…

黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day3 全网最全

你好,我是Qiuner. 为帮助别人少走弯路和记录自己编程学习过程而写博客 这是我的 github https://github.com/Qiuner ⭐️ gitee https://gitee.com/Qiuner &#x1f339; 如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 &#x1f604; (^ ~ ^) 想看更多 那就点个关注吧 我会…

Spark大数据处理技术(期末复习)

Spark大数据处理技术&#xff08;期末复习&#xff09; 1)var a:Double5;var b:Int7;那么print(a*b) 35.0 2) var a:Int5; var bif(a>6) 7 println(b) 不满足 &#xff08;&#xff09; 3)var a:Int16; var b:Int13; var cif(a>b) 5 else 7; println(c) 5 4. object …

查看 RK3568 Android SDK 版本的详细指南

目录 前提条件方法一&#xff1a;通过getprop命令查看系统属性方法二&#xff1a;通过build.prop文件查看版本信息方法三&#xff1a;查看源码中的配置文件方法四&#xff1a;通过编译输出查看版本信息附录&#xff1a;常见问题及解决方法1. adb 命令找不到设备2. getprop 或 c…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] K小姐和A先生的聚餐计划(200分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

SQL优化选对执行计划,查询速度提升1000倍 | OceanBase 应用实践

作者&#xff1a;爱可生数据库高级工程师任仲禹&#xff0c;擅长故障分析和性能优化。 本文通过一个案例&#xff0c;分享使用OceanBase时&#xff0c;SQL走错执行计划&#xff0c;而导致慢SQL的排查方法论。 案例背景 在使用OceanBase 3.2.3 版本的过程中&#xff0c;项目组反…

Java——IO流(字符流,字节流)

JavaIO的整体框架图 IO流从方向上来说&#xff0c;可以分为输入流和输出流&#xff1b; 从传输内容上来说&#xff0c;可以分为字符流和字节流 防止记混的口诀 所谓的IO&#xff0c;说白了就是数据在内存和硬盘之间的传输 输入流 %Reader %InputStream&#xff0c;从硬盘写…

C#——类和对象详情

类和对象 类 类是一种数据结构&#xff0c;它可以包含数据成员&#xff08;常量和字段&#xff09;、函数成员&#xff08;方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数&#xff09;以及嵌套类型。类类型支持继承&#xff0c;继承是一种机制&…

在 Selenium 中更改 User-Agent | 步骤与最佳实践

在 Selenium 中更改 User Agent 是许多网页抓取任务中的关键步骤。它有助于将自动化脚本伪装成常规浏览器&#xff0c;从而避免被网站检测到。本指南将带您了解如何在 Selenium 中更改 Google Chrome 的 User Agent&#xff0c;并提供最佳实践以确保您的网页抓取任务顺利进行。…

湿法消解石墨消解仪 应用化学分析领域石墨炉

石墨消解仪在化学实验中具有重要的作用。它是一种高级实验设备&#xff0c;广泛应用于化学分析领域&#xff0c;特别是在样品的前处理和测试前的样品制备过程中。 石墨消解仪采用高温高压技术&#xff0c;能够将固体样品中的有机和无机物质转化为可溶性的气体或液体形式。这种…

Helm是个啥

对于Helm的理解&#xff0c;最快的方法是对比yum。 yum是Linux的应用程序包管理器&#xff0c;可以下载应用程序&#xff0c;有时候还可以配置操作系统让下载的引用程序在后台启动&#xff0c;例如docker等。 Helm就相当于把kubernetes集群&#xff0c;看作一个Linux系统&…

Vue3表单组件el-form校验规则rules属性

Vue3表单组件el-form校验规则rules属性 一、前言1.基本用法2.示例代码3.校验规则详解4.自定义校验函数示例 二、总结 一、前言 在使用 Element UI (现在称为 Element Plus) 的表单组件 el-form 时&#xff0c;rules 属性用于定义表单项的校验规则。这些规则可以帮助你确保用户…

从0进入微服务需要了解的基础知识

文章目录 系统架构演化过程为什么要了解系统架构的演化过程技术发展认知技术选型与创新 演变过程单体架构分层-分布式集群微服务 分布式\集群\微服务 微服务中的核心要素-拆分原则项目拆分与复杂度微服务的拆分维度有哪些小结 微服务中的核心要素服务化进行拆分后一定是微服务&…

可通过小球进行旋转的十字光标(vtkResliceCursor)

前一段事件看到VTK的一个例子&#xff1a; 该案例是vtk.js写的&#xff0c;觉得很有意思&#xff0c;个人正好也要用到&#xff0c;于是萌生了用C修改VTK源码来实现该功能的想法。原本以为很简单&#xff0c;只需要修改一下vtkResliceCursor就可以了&#xff0c;加上小球&#…

自动生成列表,颜色随机 ,定时执行函数,10秒停止执行函数,按钮执行函数

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>颜色列表Color List</title><style>…

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[4]-高阶自定义模块

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[4]-高阶自定义模块 1.自定义分词器 在text_splitter文件夹下新建一个文件,文件名为您的分词器名字,比如my_splitter.py,然后在__init__.py中导入您的分词器,如下所示:from .my_splitter import MySplitter修改confi…

线程池若干问题

线程池中线程异常后&#xff0c;销毁还是复用&#xff1f; 线程池在提交任务前&#xff0c;可以提前创建线程吗&#xff1f; 线程池中线程异常后&#xff0c;销毁还是复用&#xff1f; 直接说结论&#xff0c;需要分两种情况&#xff1a; 使用execute()提交任务&#xff1a…

ZSH 配置

ZSH 配置 1. 安装 ZSH2. 安装 oh my zsh3. 安装插件3.1 autojump3.2 zsh-autosuggestions 1. 安装 ZSH sudo apt-get install zsh 完成安装后需设置当前用户使用 zsh&#xff1a; chsh -s /bin/zsh 重启后即可使用 2. 安装 oh my zsh 安装 oh my zsh 需先安装 git。 自动安装…

Neo4j图形数据库查询,Cypher语言详解

Cypher语言详解 Cypher是一种专为Neo4j图形数据库设计的声明式查询语言。它类似于SQL&#xff0c;但其设计目标是便于表达图数据库中常见的图形结构和操作。本文将详细介绍Cypher语言的基本语法、常见操作、高级功能以及使用Cypher进行图形数据分析的技巧。 1. Cypher的基本概…

gin连接redis

使用Gin框架连接Redis&#xff0c;需要先安装Redis客户端库&#xff0c;例如go-redis。然后&#xff0c;你可以创建一个Redis客户端实例&#xff0c;并在Gin路由处理函数中使用它。以下是一个简单的示例&#xff1a; 1. 首先&#xff0c;安装go-redis库&#xff1a; bash go g…