引用站外地址
nestjs中文文档
https://nest.nodejs.cn/
NestJS 是一个用于构建高效、可靠和可扩展的服务器端应用程序的框架。它使用 TypeScript 编写,但也可以使用纯 JavaScript 编写。NestJS 提供了一个结构化的方法来编写模块化代码,并且它内置了对现代 JavaScript 框架和库的支持,如 Express 和 Fastify。
NestJS的主要特点包括:
模块化:NestJS 应用程序由模块组成,每个模块都有其自己的作用域和职责。这有助于保持代码的组织和可维护性。依赖注入:NestJS 利用 TypeScript 的元数据功能来提供依赖注入,这有助于创建松耦合和可测试的代码。装饰器:NestJS 使用装饰器来简化常见的任务,如路由、中间件、控制器等。微服务架构:NestJS 支持微服务架构,可以轻松地与消息队列、数据库和其他服务进行通信。安全性:NestJS 提供了内置的安全性支持,包括身份验证和授权。测试:NestJS 有一个强大的测试框架,可以轻松编写单元测试和端到端测试。社区和生态系统:NestJS 有一个活跃的社区,提供了许多模块和插件来扩展其功能。环境搭建 安装nestjs 创建项目 运行项目 1 2 cd project-namenpm run start
项目结构 1 2 3 4 5 6 7 8 9 10 11 12 project-name ├── src │ ├── app.controller.ts │ ├── app.module.ts │ ├── app.service.ts │ └── main.ts ├── test │ └── app.e2e-spec.ts ├── package.json ├── README.md ├── tsconfig.json └── tslint.json
app.controller.ts: 控制器,处理 HTTP 请求。app.module.ts: 模块,定义了应用的各个部分,包括控制器、服务、管道、守卫等。app.service.ts: 服务,处理业务逻辑。main.ts: 入口文件,启动应用。test/app.e2e-spec.ts: 端到端测试文件。package.json: 项目依赖。README.md: 项目说明文件。tsconfig.json: 编译器配置文件。tslint.json: 代码风格检查配置文件。项目规范结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 nodejs ├── package.json ├── README.md ├── src │ │ └── constants(全局常量定义) │ │ ├──common.constants.ts │ │ └── utils(常用工具类) │ │ ├──http.util.ts │ │ └──file.util.ts │ ├── app.module.ts(模块配置文件) │ ├── common (通用模块,包含自定义装饰器、过滤器、守卫、拦截器、中间件) │ │ ├── decorators (项目通用装饰器) │ │ │ └── roles.decorator.ts │ │ ├── filters (过滤器) │ │ │ └── http-exception.filter.ts │ │ ├── guards (守卫) │ │ │ └── roles.guard.ts │ │ ├── interceptors (拦截器) │ │ │ ├── exception.interceptor.ts │ │ │ ├── logging.interceptor.ts │ │ ├── middleware (中间件) │ │ │ └── logger.middleware.ts │ │ └── pipes (管道,主要用于数据验证和类型转换) │ │ ├── parse-int.pipe.ts │ │ └── validation.pipe.ts │ ├── config (配置文件信息) │ │ ├── database.ts │ │ ├── redis.ts │ ├── jobs (高并发场景下队列处理) │ ├── main.ts (入口文件) │ ├── modules (业务代码,按目录区分模块) │ │ ├── hello │ │ │ ├── hello.controller.ts │ │ │ ├── hello.module.ts │ │ │ └── hello.service.ts │ │ └── users │ │ │ ├── dto (数据传输对象定义) │ │ │ │ └── users.create.dto.ts │ │ │ │ └── users.update.dto.ts │ │ ├── users.controller.ts (控制层) │ │ ├── users.entity.ts (映射数据库模型对象) │ │ ├── users.module.ts (模块定义) │ │ └── users.service.ts (service层) │ ├── tasks (定时任务) │ │ ├── tasks.module.ts │ │ └── tasks.service.ts │ └── templates (页面模板) ├── test (单元测试) │ ├── app.e2e-spec.ts ├── tsconfig.json
nestjs常用命令命令 描述 nest new project-name创建一个新的NestJS项目。 nest generate module module-name创建一个新的模块。 nest generate controller controller-name创建一个新的控制器。 nest generate service service-name创建一个新的服务。 nest start启动NestJS项目。 nest build编译NestJS项目。 nest start --watch启动NestJS项目并监听文件变化。 nest start --debug启动NestJS项目并进入调试模式。 nest start --watch --debug启动NestJS项目并监听文件变化并进入调试模式。 nest generate class class-name创建一个新的类。 nest generate interface-name创建一个新的接口。 nest g cl class-name创建一个新的类。 nest g interface interface-name创建一个新的接口。 nest g mo module-name创建一个新的模块。 nest g co controller-name创建一个新的控制器。 nest g s service-name创建一个新的服务。 nest g middleware middleware-name创建一个新的中间件。 nest g pipe pipe-name创建一个新的管道。 nest g guard guard-name创建一个新的守卫。 nest g decorator decorator-name创建一个新的装饰器。 nest g interface interface-name创建一个新的接口。 nest g exception exception-name创建一个新的异常过滤器。 nest g filter filter-name创建一个新的过滤器。 nest g interceptor interceptor-name创建一个新的拦截器。 nest g dto dto-name创建一个新的数据传输对象。 nest g interface interface-name创建一个新的接口。 nest g module module-name创建一个新的模块。 nest g provider provider-name创建一个新的提供者。 nest g resolver resolver-name创建一个新的解析器。 nest g resource resource-name创建一个新的crud资源。
装饰器 类装饰器装饰器 描述 @Controller用于定义一个控制器类,它将处理客户端的请求并返回响应。 @Module用于定义一个模块,它将组织应用程序的结构,包括控制器、提供者、守卫等。 @Injectable用于定义一个提供者,它将被NestJS的依赖注入系统管理。 @Middleware用于定义一个中间件,它将在请求处理管道中执行。 @Interceptor用于定义一个拦截器,它可以在方法执行前后添加额外的逻辑。 @Pipe用于定义一个管道,它可以在数据从控制器方法返回到客户端之前转换数据。 @Guard用于定义一个守卫,它可以在路由处理之前执行,用于权限验证。 @ExceptionFilter用于定义一个异常过滤器,它可以在捕获到异常时执行,用于处理错误。 @Transform用于定义一个转换器,它可以在数据从控制器方法返回到客户端之前转换数据。 @Subscription用于定义一个订阅,它将处理WebSocket消息。 @Component用于定义一个组件,它将被NestJS的依赖注入系统管理。 @Injectable用于定义一个提供者,它将被NestJS的依赖注入系统管理。
方法装饰器在NestJS中,方法装饰器主要用于增强方法的行为,例如路由处理、日志记录、权限验证等。以下是一些常用的NestJS方法装饰器:
装饰器 描述 @Get()用于定义一个HTTP GET请求的路由处理方法。 @Post()用于定义一个HTTP POST请求的路由处理方法。 @Put()用于定义一个HTTP PUT请求的路由处理方法。 @Delete()用于定义一个HTTP DELETE请求的路由处理方法。 @Patch()用于定义一个HTTP PATCH请求的路由处理方法。 @Options()用于定义一个HTTP OPTIONS请求的路由处理方法。 @Head()用于定义一个HTTP HEAD请求的路由处理方法。 @All()用于定义一个可以处理所有HTTP方法的路由处理方法。 @Param()用于提取路由参数,通常与@Get()、@Post()等装饰器一起使用。 @Body()用于提取请求体中的数据,通常用于处理POST或PUT请求。 @Query()用于提取查询字符串参数。 @Headers()用于提取请求头信息。 @Session()用于获取会话信息。 @Ip()用于获取客户端的IP地址。 @HostParam()用于获取请求的主机名。 @User()用于获取当前用户信息,通常与身份验证结合使用。 @Req()用于获取原始的请求对象。 @Res()用于获取原始的响应对象。 @Next()用于获取下一个中间件函数。 @HttpCode()用于设置响应的状态码。 @Header()用于设置响应头。 @UseGuards()用于添加守卫,用于权限验证。 @UseInterceptors()用于添加拦截器,用于在方法执行前后添加额外的逻辑。 @UseFilters()用于添加过滤器,用于处理异常或修改响应。
参数装饰器装饰器 描述 @Request() 或 @Req()注入当前的HTTP请求对象。 @Response() 或 @Res()注入当前的HTTP响应对象。 @Next()注入一个函数,调用它将执行下一个中间件。 @Session()注入当前的会话对象。 @Param(param?: string)注入路由参数,例如 @Param('id') id: string。 @Body(param?: string)注入请求体,例如 @Body('user') user: UserEntity。 @Query(param?: string)注入查询字符串参数,例如 @Query('sort') sort: string。 @Headers(param?: string)注入请求头信息,例如@Headers('Content-Type') contentType: string。 @Ip()注入客户端的IP地址。 @HostParam()注入请求的主机名。 @User()注入当前用户信息,通常与身份验证结合使用。 @HttpCode()设置响应的状态码。 @Header()设置响应头。 @Session()注入当前的会话对象。 @UploadedFile()注入上传的文件对象。 @UploadedFiles()注入上传的文件数组。
接受参数@Gethttp://localhost:3000/findOne
1 2 3 4 @Get ("/findOne" )findOne (): string { return "这是findOne方法!" ; }
Get 动态路由参数http://localhost:3000/findOne/11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Get ("/findOne/:id" )findOne (@Param ("id" ) id : string ): string { return `这是findOne方法! id=${id} ` ; } @Get ("/findOne/:id" )findOne (@Param () params : object ): string { return `这是findOne方法! dto=${params} ` ; } @Get ("/findOne/:id" )findOne (@Query ("id" ) id : string ): string { return `这是findOne方法! id=${id} ` ; }
@Posthttp://localhost:3000/create
1 2 3 4 @Post ("/create" )create (@Body () createCatDto : CreateCatDto ): string { return `这是create方法! createCatDto=${createCatDto} ` ; }
@Queryhttp://localhost:3000/user/test/query?id=124124&name=张三
1 2 3 4 5 @Get ('/test/query' )findOneByQuery (@Query () query: any ) { console .log (query); return query; }
@Requesthttp://localhost:3000/user/test/query?id=124124&name=张三
1 2 3 4 5 @Get ('req/query' )findOne (@Req () req : Request ): string { console .log (req.query ); return req.query ; }
配置静态资源 在NestJS中,你可以通过配置静态资源来提供文件,如图片、CSS、JavaScript等。NestJS使用了内置的Express或Fastify服务器,因此你可以使用它们的中间件来配置静态资源。
安装所需的包:确保你的项目中安装了@nestjs/platform-express包,因为NestJS默认使用Express作为其HTTP平台。1 npm install --save @nestjs/platform-express
在模块中main.ts文件中,导入静态资源中间件:在你的模块文件中,导入并使用NestFastifyApplication的register方法来配置静态资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import { join } from 'path' ;const assetDir = (dir ) => join (__dirname, '..' , dir); async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.useStaticAssets (assetDir ('public' ), { prefix : '/assets/' , }); await app.listen (3000 ); } bootstrap ();
在上面的例子中,path.join(__dirname, 'public')是包含静态资源的目录的绝对路径,{ prefix: '/assets/' }是一个可选的配置对象,用于设置静态资源的URL前缀。
创建静态资源目录:在你的项目根目录下创建一个名为public/image/xxx.jpg的文件夹,并将你的静态资源文件(如图片、CSS、JavaScript等)放入该文件夹。
访问静态资源:在浏览器中访问http://localhost:3000/image/xxx.jpg!如果配置了prefix前缀的话,那么访问的路径则应该是http://localhost:3000/assets/image/img1.jpg。
配置模版引擎 安装模版引擎在main.ts模块儿中设置模版引擎(app.setViewEngine('ejs'))1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import { join } from 'path' ;const assetDir = (dir ) => join (__dirname, '..' , dir); async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.useStaticAssets (assetDir ('public' ), { prefix : '/assets/' , }); app.setViewEngine ('ejs' ); await app.listen (3000 ); } bootstrap ();
在根目录中创建 views目录,并在views目录下创建/default/index.ejs文件!文件内容如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <center > <h3 > 模版引擎测试</h3 > </center > <center > <p > Hello, Nest.js!</p > <p > This is a simple demo of Nest.js template engine.</p > <p > 名称: <%=name%></p > <p > 年龄: <%=age%></p > </center > </body > </html >
在controller中通过@Render()来引入模版引擎!1 2 3 4 5 @Get ("/getTemplate" )@Render ("default/index" )getTemplate () : object { return { name : "张三" , age : 18 }; }
访问http://localhost:3000/getTemplate即可看到模版引擎渲染的页面。 配置session 众所周知,HTTP协议是无状态的,这意味着每次浏览器请求服务器的时候,服务器并不知道这个请求与之前的请求是否来自同一个用户。这就像你每次到咖啡店,咖啡师都不记得你喜欢什么口味的咖啡一样。
为了解决这个问题,Session被设计来跟踪和保持用户的状态。Session可以被理解为服务器端存储的一块空间,每个用户都有一个独立的Session空间,用来保存用户相关的信息,比如用户的登录状态、购物车中的商品等。
当用户首次访问服务器时,服务器会为此用户创建一个独一无二的Session,并生成一个唯一的标识符(通常称为session ID)。随后,这个session ID会被存储在用户浏览器的cookie中。此后,用户的每次请求中都会携带这个session ID,服务器通过这个ID获取对应的Session信息,以识别用户身份。
身份验证:通过Session检查用户是否登录,并获取用户的登录信息。状态保持:无论用户在站点中浏览哪里,都能保持其特定的交互状态,如购物车数据或用户设置。安全:Session可以在服务器端进行加密处理,保证敏感信息的安全。安装插件 1 2 npm install express-session --save npm install @types/express-session --save-dev
main.ts中引入session1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import * as session from "express-session" ;async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.use (session ({ secret : "ppxiong" , name : "ppxiong.sid" , cookie : { maxAge : 60000 }, rolling : true , })) } bootstrap ()
session验证码案例安装svg-captcha svg-captcha 是一款验证码插件!
1 npm install svg-captcha --save
controller中使用http://localhost:3000/user/codehttp://localhost:3000/user/login
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Get ('/code' )createCode (@Req () req, @Res () res, @Session () session ) { const captcha = SvgCaptcha .create ({ size : 4 , fontSize : 50 , width : 100 , height : 40 , background : '#f0f0f0' , noise : 2 , color : true , ignoreChars : '0o1i' , }); session.code = captcha.text ; res.type ('application/json' ); console .log ("createCode!!!!!!!!!!!!!!!!" , captcha.text ) res.send ({code : captcha.text , image : captcha.data }); }
1 2 3 4 5 6 7 8 @Post ('/login' )login (@Body () body, @Res () res, @Session () session, ) { const { username, password, code } = body; const { code : sessionCode } = session; res.type ('application/json' ); res.send ({ code : 200 , message : '请求成功!' , success : true }) }
提供者(service) 在 NestJS 中,"提供者"(Providers)是一个核心概念,它指的是可以被注入到其他组件中的任何类。提供者可以是服务(Service)、存储库(Repository)、工厂(Factory)、助手(Helper)等。它们通常用于封装业务逻辑、数据访问、第三方服务集成等。
具体在xxx.module.ts文件中 @Module({providers: [xxxService]}) 配置!provide: 提供者的 name! 可以是 [useClass useValue, useFactory]!
基本使用 CatsService CatsController 1 2 3 4 5 6 7 8 9 10 import { Injectable } from '@nestjs/common' ;@Injectable ()export class CatsService { private readonly cats : string [] = []; findAll (): string [] { return this .cats ; } }
1 2 3 4 5 6 7 8 9 10 11 12 import { Controller , Get } from '@nestjs/common' ;import { CatsService } from './cats.service' ;@Controller ('cats' )export class CatsController { constructor (private catsService: CatsService ) {} @Get () async findAll (): Promise <string []> { return this .catsService .findAll (); } }
将CatsService注入到CatsController中,通过constructor (private catsService: CatsService)方法注入。
service自定义名称user.module.ts user.controller.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { Module } from '@nestjs/common' ;import { UserService } from './user.service' ;import { UserController } from './user.controller' ;@Module ({ controllers : [UserController ], providers : [UserService ,{ provide : 'customService' , useClass : UserService }], }) export class UserModule {}
1 2 3 4 @Controller ('user' )export class UserController { constructor ( @Inject ('customService' ) private readonly userService: UserService ) {} }
service工厂模式user.module.ts user.controller.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { Module } from '@nestjs/common' ;import { UserService } from './user.service' ;import { UserController } from './user.controller' ;@Module ({ controllers : [UserController ], providers : [ { provide : 'userServiceFactory' , useFactory : (connection: Connection ) => { return connection.getCustomRepository (UserRepository ); }, inject : [Connection ], }, UserService , ], }) export class UserModule {}
1 2 3 4 5 6 @Controller ('user' )export class UserController { constructor ( @Inject ('userServiceFactory' ) private readonly userService: UserService, ) {}}
模块 在 NestJS 中,@Module 装饰器用于组织应用程序的结构。它允许你将相关的组件(如控制器(controller)、提供者(service)、中间件等)组合在一起,形成一个模块。每个 NestJS 应用程序至少有一个模块,即根模块(通常是 AppModule),它引导整个应用程序。
模块是组织代码和定义应用程序边界的一种方式。通过模块,你可以将应用程序分解为更小、更易于管理的部分,这有助于保持代码的清晰和可维护性。
创建order模块(含CRUD)操作
创建order完成后,在order.module.ts中自动引入order.controller.ts和order.service.ts!
共享模块(module) 在其它模块(app.controller.ts)下,引入order.module.ts!exports: [OrderService] 共享模块时, 需要先导出模块!
order.module.ts order.controller.ts order.service.ts 1 2 3 4 5 6 7 8 9 10 11 import { Module } from '@nestjs/common' ;import { OrderService } from './order.service' ;import { OrderController } from './order.controller' ;@Module ({ controllers : [OrderController ], providers : [OrderService ], exports : [OrderService ], }) export class OrderModule {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { Controller , Get } from '@nestjs/common' ;import { OrderService } from './order.service' ;@Controller ('order' )export class OrderController { constructor (private readonly orderService: OrderService ) { } @Get ('/all' ) async getAllOrders (): Promise <any > { return 'get order all!' ; } }
1 2 3 4 5 6 7 8 9 10 import { Injectable } from '@nestjs/common' ;@Injectable ()export class OrderService { constructor ( ) {} getOrderAll (): string { return "Service This is order all!!!" ; } }
1 2 3 4 5 @Module ({ controllers : [OrderController ], providers : [OrderService ], exports : [OrderService ], })
其中exports,向外暴露了OrderService,这样其他模块就可以使用OrderService了。
app.controller.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { Controller , Get , Query , Render } from '@nestjs/common' ;import { AppService } from './app.service' ;import { OrderService } from './order/order.service' ;@Controller ("/hello" )export class AppController { constructor ( private readonly appService: AppService, private readonly orderService: OrderService ) {} @Get ("/order" ) getOrder () : string { return this .orderService .getOrderAll (); } }
全局模块 接下来会使用@Global()装饰器来定义全局模块!
创建config.module.ts 在根目录中config文件夹下创建config.module.ts文件!
config.module.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import { Global , Module } from "@nestjs/common" ;@Global ()@Module ({ providers : [ { provide : "CONFIG" , useValue : { baseUrl : '/api' }, }, ], exports : [ { provide : "CONFIG" , useValue : { baseUrl : '/api' }, }, ] }) export class ConfigModule { constructor ( ) { console .log ("ConfigModule created" ); } }
在app.module.ts中引用 app.module.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { Module } from '@nestjs/common' ;import { AppController } from './app.controller' ;import { AppService } from './app.service' ;import { ClassifyModule } from './classify/classify.module' ;import { UserModule } from './user/user.module' ;import { OrderModule } from './order/order.module' ;import { ConfigModule } from './config/config.module' ;@Module ({ imports : [UserModule , ClassifyModule , OrderModule , ConfigModule ], controllers : [AppController ], providers : [AppService ], }) export class AppModule {}
在imports 引入 configModule 之后, 其他模块都可以直接使用 ConfigModule 中的 CONFIG 了!
在order.controller.ts中使用 @Inject('CONFIG') private readonly config: ConfigModule 注入 ConfigModule 中的 CONFIG!
order.controller.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import { Controller , Get , Inject } from '@nestjs/common' ;import { OrderService } from './order.service' ;import { ConfigModule } from 'src/config/config.module' ;@Controller ('order' )export class OrderController { constructor ( private readonly orderService: OrderService, @Inject ('CONFIG' ) private readonly config: ConfigModule, ) { } @Get ('/all' ) async getAllOrders (): Promise <any > { return 'get order all!' ; } @Get ('/testGlobalModule' ) async tesGlobalModule ( ) { return this .config ; } }
中间件middleware 在 NestJS 中,中间件是一个函数,它在路由处理程序之前被调用,可以用来执行一些通用的任务,比如日志记录、身份验证、请求处理等。中间件可以访问请求对象(Request)、响应对象(Response)和应用程序请求-响应循环中的下一个中间件函数(next)。
next 函数类似与vue-router中的导航守卫(beforeEach)! 当调用next函数时,会执行通过路由请求,否则会挂起请求!
通过nest --help查看NestJS的命令行选项!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ┌───────────────┬─────────────┬──────────────────────────────────────────────┐ │ name │ alias │ description │ │ application │ application │ Generate a new application workspace │ │ class │ cl │ Generate a new class │ │ configuration │ config │ Generate a CLI configuration file │ │ controller │ co │ Generate a controller declaration │ │ decorator │ d │ Generate a custom decorator │ │ filter │ f │ Generate a filter declaration │ │ gateway │ ga │ Generate a gateway declaration │ │ guard │ gu │ Generate a guard declaration │ │ interceptor │ itc │ Generate an interceptor declaration │ │ interface │ itf │ Generate an interface │ │ library │ lib │ Generate a new library within a monorepo │ │ middleware │ mi │ Generate a middleware declaration │ │ module │ mo │ Generate a module declaration │ │ pipe │ pi │ Generate a pipe declaration │ │ provider │ pr │ Generate a provider declaration │ │ resolver │ r │ Generate a GraphQL resolver declaration │ │ resource │ res │ Generate a new CRUD resource │ │ service │ s │ Generate a service declaration │ │ sub-app │ app │ Generate a new application within a monorepo │ └───────────────┴─────────────┴──────────────────────────────────────────────┘
局部中间件 创建logger.middleware.ts 1 nest g middleware logger
/middleware/logger.middleware.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 import { Injectable , NestMiddleware } from '@nestjs/common' ;import { Request , Response , NextFunction } from 'express' ;@Injectable ()export class LoggerMiddleware implements NestMiddleware { use (req: Request, res: Response, next: () => void ) { next (); } }
在order.module.ts 中引用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import { Module , NestModule } from '@nestjs/common' ;import { OrderService } from './order.service' ;import { OrderController } from './order.controller' ;import { LoggerMiddleware } from 'src/middleware/logger.middleware' ;@Module ({ controllers : [OrderController ], providers : [OrderService ], exports : [OrderService ], }) export class OrderModule implements NestModule { configure (consumer ) { consumer.apply (LoggerMiddleware ).forRoutes ('*' ); } }
全局中间件 创建global.middleware.ts 1 2 3 4 5 6 import { Request , Response , NextFunction } from "express" export const globalMiddleware = (req: Request, Response: Response, next: NextFunction ) => { console .log ("Global middleware is running" ) console .log (`Global middleware Request... ${req.method} ${req.url} ${req.originalUrl} ` ); next () }
在main.ts 中引用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import { join } from 'path' ;import { globalMiddleware } from './middleware/global.middleware' ;const assetDir = (dir ) => join (__dirname, '..' , dir); async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.use (globalMiddleware); await app.listen (3000 ); } bootstrap ();
配置第三方中间件 安装cors中间件 1 2 pnpm i cors --save pnpm i @types/cors --save-dev
在main.ts 中引用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import { join } from 'path' ;import { globalMiddleware } from './middleware/global.middleware' ;import * as cors from 'cors' ;const assetDir = (dir ) => join (__dirname, '..' , dir); async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.use (globalMiddleware); app.use (cors ()); await app.listen (3000 ); }
附件上传 安装插件 1 2 pnpm i multer --save pnpm i multer @types/multer --save
multer 是一个Node.js 中处理 multipart/form-data 上传的中间件。它可以上传文件、存储文件、验证文件等。@types/multer 是 multer 的类型定义文件,可以让TypeScript 识别multer 的类型和代码块提示!。
创建upload模块 配置和使用 在 upload.module.ts 和 upload.controller.ts 中配置和使用!
upload.module.tsMulterModule.register(): 注册 上传模块!diskStorage(): 存储上传文件到指定目录 !upload.controller.ts@Post('/album'): 上传文件路由 !@UploadedFile() file: 获取上传文件 !@UseInterceptors(FileInterceptor('file')): 上传文件中间件 !请求路径: http://localhost:3000/upload/album 请求参数: file: 文件 blob!
访问上传静态资源 1 2 3 4 5 6 async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.useStaticAssets (assetDir ('uploadFiles' ), { prefix : '/assets/uploadFiles/' , }); }
路径访问实例: : http://localhost:3000/assets/uploadFiles/1717295349937-file-9189.jpg
附件下载 直接下载 以下方式下载路径写死的,需要根据实际情况修改!
通过装饰器 @Res() res的download方法来进行直接下载!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Get ('/download' )async download (@Res () res ) { const fileUrl = join (__dirname, '../uploaFiles/1717311840261-file-9216.jpg' ) try { res.download (fileUrl); } catch (error) { console .log ("download error" , error) return { code : 500 , message : '下载失败' , error } } }
文件流下载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Get ('/stream' )async stream (@Res () res ) { const fileUrl = join (__dirname, '../uploaFiles/1717311840261-file-9216.jpg' ) try { const readStream = require ('fs' ).createReadStream (fileUrl) readStream.pipe (res) } catch (error) { console .log ("stream error" , error) return { code : 500 , message : '下载失败' , error } } }
rxjs在 NestJS 中,RxJS 用于处理异步操作和事件流。例如,当你需要处理 HTTP 请求、数据库操作或任何其他异步任务时,你可以使用 RxJS的 Observables 来创建和管理这些异步数据流。
Observables: 异步数据流 。Subscription: 订阅 监听 Observables 。Operators: 操作符 。Subjects: 主体 。Schedulers: 调度器 。创建rxjs.ts 在 src 目录下创建 rxjs.ts 文件!
需要通过ts-node方式来执行rxjs.ts文件!
运行rxjs.ts
导入模块
1 2 import { Observable , of , from , interval, take } from 'rxjs' ;import { map, filter, tap } from 'rxjs/operators' ;
案例一Observable 使用迭代器next发出通知,并使用complete来完成通知!
案例一 1 2 3 4 5 6 7 8 9 10 11 const source = new Observable ((observer ) => { observer.next ('Hello' ); observer.next ('World' ); setTimeout (() => { observer.next ('我是异步函数!' ) observer.complete (); }, 1000 ); }); source.subscribe ((value ) => console .log (value));
案例二of 使用of()函数来创建 Observable 对象,并通过subscribe()订阅它!
1 2 3 4 5 6 7 const source2 = of ('Hello' , 'World' );source2.subscribe ((value ) => console .log (value));
案例三from 使用from()函数来创建 Observable 对象,并通过subscribe()订阅它!
1 2 3 4 5 6 7 8 9 10 const source3 = from ([1 , 2 , 3 , 4 , 5 ]);source3.subscribe ((value ) => console .log (value));
案例四interval 使用interval()函数来创建 Observable 对象,并通过subscribe()订阅它!
1 2 3 4 5 6 7 8 9 10 11 12 13 const source4 = interval (1000 );source4.pipe (take (5 )).subscribe ((value ) => console .log (value));
案例五map 使用map()操作符来映射 Observable 对象,并通过subscribe()订阅它!
1 2 3 const source5 = of ('Hello' , 'World' ).pipe (map ((value ) => value.toUpperCase ()));source5.subscribe ((value ) => console .log (value));
案例六info 使用filter()操作符来过滤 Observable 对象,并通过subscribe()订阅它!
1 2 3 4 const source6 = of ('Hello' , 'World' , '你好' , '안녕하세요' , 'こんにちは' , '안녕하세요' ).pipe (filter ((value ) => value.length > 2 ));source6.subscribe ((value ) => console .log (value));
案例七tap 使用tap()操作符来拦截 Observable 对象,并通过subscribe()订阅它!
1 2 3 const source7 = of ('Hello' , 'World' ).pipe (tap ((value ) => console .log (`before: ${value} ` )));source7.subscribe ((value ) => console .log (`after: ${value} ` ));
取消订阅 通过subscription.unsubscribe() 来取消监听机制!
1 2 3 4 5 6 7 8 9 let subscription = interval (1000 ).pipe ( map ((value ) => { return { num : value }}) ).subscribe (e => { console .log ("e: " , e) if ( e.num === 5 ) { subscription.unsubscribe (); } });
响应拦截器 在Nest框架中,拦截器(Interceptors)是一种强大的机制,它允许你在请求处理流程中的某个点上拦截和修改请求或响应。拦截器可以用于日志记录、错误处理、权限验证、数据转换等多种场景。
要创建一个响应拦截器,你需要实现NestInterceptor接口。这个接口要求你实现一个intercept方法,该方法接收两个参数:ExecutionContext和CallHandler。
创建response.interceptor.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { CallHandler , ExecutionContext , Injectable , NestInterceptor } from "@nestjs/common" ;import { Observable , map } from "rxjs" ;@Injectable ()export class ResponseInterceptor <T> implements NestInterceptor { intercept (context: ExecutionContext, next: CallHandler ) { console .log ("Response interceptor" , next); return next.handle ().pipe (map (data => ({ data : data, message : "请求成功!" , success : true }))); } }
在这个例子中,ResponseInterceptor会在请求处理之后处理响应结果。intercept方法调用next.handle()来继续请求处理流程。next.handle()返回一个Observable,你可以在这个Observable上使用RxJS操作符来修改响应。在这个例子中,我们使用了map操作符来定义响应结果!
全局拦截器 在 main.ts中引入ResponseInterceptor,通过app.useGlobalInterceptors()方法注册全局拦截器!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import { ResponseInterceptor } from './interceptor/response' ;const assetDir = (dir ) => join (__dirname, dir); const dirName = "uploaFiles" async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.useGlobalInterceptors (new ResponseInterceptor ()); await app.listen (3000 ); } bootstrap ();
请求路径: http://localhost:3000/user
1 2 3 4 5 6 7 8 { "data" : "This action returns all user" , "message" : "请求成功!" , "success" : true }
局部拦截器 在控制器 [controller]中引入ResponseInterceptor,通过@UseInterceptors()方法注册局部拦截器!
1 2 3 4 5 6 7 8 9 10 11 import { Controller , Get , UseInterceptors } from '@nestjs/common' ;import { ResponseInterceptor } from './response.interceptor' ;@Controller ('cats' )@UseInterceptors (ResponseInterceptor )export class CatsController { @Get () findAll (): string { return 'This action returns all cats' ; } }
异常拦截器 在NestJS中,异常过滤器(Exception Filters)是一种特殊类型的中间件,用于处理应用程序中抛出的异常。它们允许你为应用程序中的不同异常类型定义统一的处理逻辑,从而提供更加健壮和用户友好的错误处理机制。
要创建一个异常过滤器,你需要实现ExceptionFilter接口。这个接口要求你实现一个catch方法,该方法接收两个参数:exception和host。
创建http-exception.filter.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import { ArgumentsHost , Catch , ExceptionFilter , HttpException } from "@nestjs/common" ;import { Request , Response } from "express" ;@Catch (HttpException )export class HttpErrorFilter implements ExceptionFilter { catch (exception : HttpException , host : ArgumentsHost ) { const ctx = host.switchToHttp (); const response = ctx.getResponse <Response >(); const request = ctx.getRequest <Request >(); const status = exception.getStatus (); const message = exception.message ; const error = exception.getResponse (); response.status (status).json ({ statusCode : status, timestamp : new Date ().toISOString (), path : request.url , message, success : false , error }); } }
全局异常拦截器 在 main.ts中引入HttpErrorFilter,通过app.useGlobalFilters()方法注册全局异常拦截器!
1 2 3 4 5 6 7 8 9 10 11 12 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import { HttpErrorFilter } from './interceptor/http-exception.filter.ts' ;async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.useGlobalFilters (new HttpErrorFilter ()); await app.listen (3000 ); } bootstrap ();
请求路径: http://localhost:3000/aaa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { "statusCode" : 404 , "timestamp" : "2024-06-03T09:49:28.399Z" , "path" : "/aaa" , "message" : "Cannot GET /aaa" , "success" : false , "error" : { "message" : "Cannot GET /aaa" , "error" : "Not Found" , "statusCode" : 404 } }
局部异常拦截器 在控制器 [controller]中引入HttpErrorFilter,通过@UseFilters()方法注册局部异常拦截器!
1 2 3 4 5 6 7 8 9 10 11 import { Controller , Get , UseFilters } from '@nestjs/common' ;import { HttpErrorFilter } from './http-exception.filter' ;@Controller ('cats' )@UseFilters (HttpErrorFilter )export class CatsController { @Get () findAll (): string { throw new HttpException ('This action returns all cats' , 404 ); } }
管道 数据转换 可以将前端传入的参数类型进行格式转换!
1 2 3 4 @Get (':id' )findOne (@Param ('id' , ParseIntPipe) id: number ) { return this .userService .findOne (+id); }
ParseIntPipe 用于将参数转换为number类型! 除了 ParseIntPipe 以外还有其他类型转换!
ParseBoolPipeParseArrayPipeParseUUIDPipeParseEnumPipeParseDatePipeParseJsonPipeParseFloatPipeDefaultValuePipeValidationPipe局部数据验证 类型检查、数据格式检查、数据长度检查、数据范围检查等! 需要安装class-validator和class-transformer来进行格式校验!
class-validator: 用于数据类型校验!class-transformer: 用于数据转换将接受的参数映射到实体类!安装插件 1 pnpm i class-validator class-transformer -D
创建login模块 创建login自定义管道 自定义管道可以对请求的参数进行校验和处理!
1 nest g pi login/login-validation
编辑create.login.dto.ts 在dto实体类中加入class-validator的装饰器!
IsNotEmpty: 校验是否为空!IsNumber: 校验是否为number类型!IsString: 校验是否为string类型!Length: 校验字符串长度!1 2 3 4 5 6 7 8 9 10 11 12 import { IsNotEmpty , IsNumber , IsString , Length } from 'class-validator' ;export class CreateLoginDto { @IsString () @IsNotEmpty () @Length (5 ,10 ,{ message : "用户名长度必须在5到10个字符之间!" }) username : string ; @IsString () password : string ; }
编辑login.pipe.ts login.pipe.ts文件为自定义管道,其中transform方法用于对请求的参数进行校验和处理。 其中value是请求的参数,metadata是请求的元数据。metadata元数据中包含: { metatype: [class CreateLoginDto], type: 'body', data: undefined }
请求类型(type) 请求实体dto(metatype) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import { ArgumentMetadata , HttpException , HttpStatus , Injectable , PipeTransform } from '@nestjs/common' ;import { plainToInstance } from 'class-transformer' ;import { validate } from 'class-validator' ;@Injectable ()export class LoginPipe implements PipeTransform { async transform (value: any , metadata: ArgumentMetadata ) { console .log ('LoginPipe' , value, metadata); const dto = plainToInstance (metadata.metatype , value); console .log ("dto" , dto) const validateResult = await validate (dto); console .log ("validateResult" , validateResult) if ( validateResult.length ) { throw new HttpException ( { errors : validateResult, message : 'Validation failed params is not valid pass!' }, HttpStatus .BAD_REQUEST ); } return value; } }
通过class-transformer中的plainToInstance方法进行参数和实体之间数据映射! 通过class-validator中的validate方法进行dto实体的数据校验!
编辑login.controller.ts 在controller中引入pipe自定义管道,并放在参数装饰器中@Body(LoginPipe)!
1 2 3 4 @Post ()create (@Body (LoginPipe) createLoginDto: CreateLoginDto ) { return this .loginService .create (createLoginDto); }
校验结果 请求路径: http://localhost:3000/login 请求参数:
1 2 3 4 { "username" : "张三" , "password" : 123456 }
validateResult 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 { "statusCode" : 400 , "timestamp" : "2024-06-04T02:33:54.469Z" , "path" : "/login" , "message" : "Validation failed params is not valid pass!" , "success" : false , "error" : { "errors" : [ { "target" : { "username" : "张三" , "password" : 123456 } , "value" : "张三" , "property" : "username" , "children" : [ ] , "constraints" : { "isLength" : "用户名长度必须在5到10个字符之间!" } } , { "target" : { "username" : "张三" , "password" : 123456 } , "value" : 123456 , "property" : "password" , "children" : [ ] , "constraints" : { "isString" : "password must be a string" } } ] , "message" : "Validation failed params is not valid pass!" } }
全局数据验证 在入口文件main.ts中引入ValidationPipe
1 2 3 4 5 6 7 8 9 10 11 12 import { NestFactory } from '@nestjs/core' ;import { AppModule } from './app.module' ;import { NestExpressApplication } from '@nestjs/platform-express' ;import { ValidationPipe } from '@nestjs/common' ;async function bootstrap ( ) { const app = await NestFactory .create <NestExpressApplication >(AppModule ); app.useGlobalPipes (new ValidationPipe ()) await app.listen (3000 ); } bootstrap ();
校验结果
validateResult 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { "statusCode" : 400 , "timestamp" : "2024-06-04T02:57:45.992Z" , "path" : "/login" , "message" : "Bad Request Exception" , "success" : false , "error" : { "message" : [ "用户名长度必须在5到10个字符之间!" , "password must be a string" ] , "error" : "Bad Request" , "statusCode" : 400 } }
守卫 在 NestJS 中,守卫(Guards)是用于控制对特定路由的访问的中间件。它们在路由处理程序执行之前运行,并且可以访问请求对象(Request)、响应对象(Response)以及控制器的上下文(Context)。守卫可以执行各种任务,比如验证用户身份、检查权限、管理请求的生命周期等。
执行访问控制逻辑:根据用户的角色、权限或其他条件来决定是否允许访问某个路由。修改请求对象:在处理程序执行之前,可以对请求对象进行修改。决定是否继续执行请求:守卫可以决定请求是否应该继续传递给下一个中间件或处理程序。要创建一个守卫,你需要实现 CanActivate 接口,该接口有一个 canActivate 方法。这个方法应该返回一个布尔值,表示是否允许请求继续执行。
创建守卫 role.guard.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 import { CanActivate , ExecutionContext , Injectable } from '@nestjs/common' ;import { Observable } from 'rxjs' ;@Injectable ()export class RoleGuard implements CanActivate { canActivate ( context : ExecutionContext , ): boolean | Promise <boolean > | Observable <boolean > { const request = context.switchToHttp ().getRequest (); console .log ("RoleGuard" ,request.user ); return true ; } }
局部守卫 在user.controller.ts中引入守卫 局部守卫 1 2 3 4 5 6 7 8 9 10 11 12 import { Controller , Get , UseGuards } from '@nestjs/common' ;import { RoleGuard } from 'src/role/role.guard' ;@Controller ('user' )@UseGuards (RoleGuard )export class UserController { @Get () @SetMetadata ('roles' , ['admin' ]) findAll ( ) { return this .userService .findAll (); } }
UseGuards 装饰器来引入守卫。@SetMetadata('role', ['admin']) 装饰器来设置角色信息,并将meta data传送至role.guard.ts守卫中通过Reflector来获取。
在role.guard.ts中获取角色信息 role.guard.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { CanActivate , ExecutionContext , Injectable } from '@nestjs/common' ;import { Reflector } from '@nestjs/core' ;import { Request } from 'express' ;import { Observable } from 'rxjs' ;@Injectable ()export class RoleGuard implements CanActivate { constructor (private reflector: Reflector ) {} canActivate ( context : ExecutionContext , ): boolean | Promise <boolean > | Observable <boolean > { const request = context.switchToHttp ().getRequest <Request >(); const roles = this .reflector .get <string []>('roles' , context.getHandler ()); console .log ("RoleGuard" ,roles); return true ; } }
全局守卫 在main.ts中引入role.guard.ts, 并通过app.useGlobalGuards()方法注册全局守卫!
1 app.useGlobalGuards (new RoleGuard ())
自定义装饰器 创建自定义装饰器
自定义装饰器 1 2 3 import { SetMetadata } from '@nestjs/common' ;export const Role = (...args: string [] ) => SetMetadata ('role' , args);
在user.controller.ts使用
1 2 3 4 5 6 7 8 9 10 11 12 13 import { Controller , Get , UseGuards } from '@nestjs/common' ;import { RoleGuard } from 'src/role/role.guard' ;@Controller ('user' )@UseGuards (RoleGuard )export class UserController { @Get () @Role ('admin' ) findAll ( ) { return this .userService .findAll (); } }
swagger文档Swagger 允许你描述 API 的结构,以便机器可以读取它们。这意味着你可以自动生成文档、客户端库等。 在 NestJS 中使用 Swagger,你可以通过安装 @nestjs/swagger 包来实现。以下是使用 Swagger 的基本步骤:
安装 @nestjs/swagger 包:1 npm install @nestjs/swagger swagger-ui-express @types/swagger-schema-official -D
@types/swagger-schema-official 类型声明,有了这个才会有代码提示! 在你的NestJS 应用中导入 SwaggerModule 并配置它:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import { NestFactory } from '@nestjs/core' ;import { SwaggerModule , DocumentBuilder } from '@nestjs/swagger' ;import { AppModule } from './app.module' ;async function bootstrap ( ) { const app = await NestFactory .create (AppModule ); const options = new DocumentBuilder () .setTitle ('NestJS API' ) .setDescription ('The NestJS API description' ) .setVersion ('1.0' ) .addTag ('api' ) .build (); const document = SwaggerModule .createDocument (app, options); SwaggerModule .setup ('api-docs' , app, document ); await app.listen (3000 ); } bootstrap ();
在你的控制器中使用装饰器来描述路由和参数:controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import { Controller , Get , Query , Body , Param , Description } from '@nestjs/common' ;import { ApiTags , ApiOperation , ApiParam , ApiResponse } from '@nestjs/swagger' ;@Controller ('cats' )@ApiTags ('cats' )export class CatsController { @Get () @ApiOperation ({ summary : '获取所有猫的信息' }) findAll (): string { return 'This action returns all cats' ; } @Get (':id' ) @ApiOperation ({ summary : '获取一只猫的信息' }) findOne (@Param ('id' ) id : string ): string { return `This action returns a #${id} cat` ; } @Post () @ApiOperation ({ summary : '创建一只猫' }) create (@Body () body): string { return body; } @Delete (':id' ) @ApiOperation ({ summary : '删除一只猫' }) remove (@Param ('id' ) id : string ): string { return `This action removes a #${id} cat` ; } }
访问 Swagger UI:http://localhost:3000/api-docs swagger中常用的装饰器用于给控制器或方法添加标签,以便在 Swagger UI 中对 API 进行分组和分类。
1 2 3 4 5 @ApiTags ('users' )@Controller ('users' )export class UsersController { }
@ApiOperation用于描述控制器方法的详细信息,包括摘要、描述、响应等。。
1 2 3 4 5 @ApiOperation ({ summary : '获取用户信息' , description : '根据用户ID获取用户信息' })@Get (':id' )async getUserById (@Param ('id' ) id: string ) { }
@ApiParam用于描述控制器方法的参数,包括参数名称、类型、是否必须等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @ApiTags ('users' )@Controller ('users' )export class UsersController { @Get () @ApiOperation ({ summary : '获取用户列表' }) @ApiParam ({ name : 'limit' , required : false , description : '限制返回的用户数量' , example : 10 }) @ApiParam ({ name : 'offset' , required : false , description : '偏移量' , example : 0 }) async getUsers ( @Param ('limit' , new ParseIntPipe()) limit: number , @Param ('offset' ) offset: number = 0 ) { } }
@ApiQuery用于描述控制器方法的查询参数,通常与 @Query() 装饰器一起使用。
1 2 3 4 5 6 7 8 9 10 @Get ()@ApiOperation ({ summary : '获取用户列表' })@ApiQuery ({ name : 'limit' , required : false , description : '限制返回的用户数量' , example : 10 })@ApiQuery ({ name : 'offset' , required : false , description : '偏移量' , example : 0 })async getUsers ( @Query ('limit' , new ParseIntPipe()) limit: number , @Query ('offset' ) offset: number = 0 ) { }
@ApiBody用于描述控制器方法的请求体,通常与 @Body() 装饰器一起使用。
1 2 3 4 5 6 7 8 @Post ()@ApiOperation ({ summary : '创建新用户' })async createUser ( @ApiBody ({ description: '用户信息' }) @Body () createUserDto: CreateUserDto ) { }
@ApiProperty用于描述实体类的属性,包括名称、类型、描述、是否必填等。
1 2 3 4 5 6 7 export class CreateUserDto { @ApiProperty ({ description : '用户名' , example : 'john' }) username : string ; @ApiProperty ({ description : '密码' , example : '123456' }) password : string ; }
@ApiResponse用于描述控制器方法的响应,包括状态码、描述和模式。
1 2 3 4 5 6 @Post ()@ApiOperation ({ summary : '创建新用户' })@ApiResponse ({ status : 201 , description : '用户创建成功' })async createUser (@Body () createUserDto: CreateUserDto ) { }
@ApiOkResponse用于描述控制器方法的正常响应(通常是 HTTP 200 状态码)。
1 2 3 4 5 6 @Get (':id' )@ApiOperation ({ summary : '获取用户信息' })@ApiOkResponse ({ description : '用户信息' , type : User })async getUserById (@Param ('id' ) id: string ) { }
@ApiBadRequestResponse用于描述控制器方法的错误请求响应(通常是 HTTP 400 状态码)。
1 2 3 4 5 6 @Post ()@ApiOperation ({ summary : '创建新用户' })@ApiBadRequestResponse ({ description : '无效的请求体' })async createUser (@Body () createUserDto: CreateUserDto ) { }
@ApiUnauthorizedResponse用于描述控制器方法的未授权响应(通常是 HTTP 401 状态码)。
1 2 3 4 5 6 @Get ()@ApiOperation ({ summary : '获取用户列表' })@ApiUnauthorizedResponse ({ description : '未授权访问' })async getUsers ( ) { }
@ApiForbiddenResponse用于描述控制器方法的禁止访问响应(通常是 HTTP 403 状态码)。
1 2 3 4 5 6 @Get ()@ApiOperation ({ summary : '获取用户列表' })@ApiForbiddenResponse ({ description : '禁止访问' })async getUsers ( ) { }
@ApiNotFoundResponse用于描述控制器方法的未找到响应(通常是 HTTP 404 状态码)。
1 2 3 4 5 6 @Get (':id' )@ApiOperation ({ summary : '获取用户信息' })@ApiNotFoundResponse ({ description : '用户不存在' })async getUserById (@Param ('id' ) id: string ) { }
@ApiConflictResponse用于描述控制器方法的冲突响应(通常是 HTTP 409 状态码)。
1 2 3 4 5 6 @Post ()@ApiOperation ({ summary : '创建新用户' })@ApiConflictResponse ({ description : '用户名已存在' })async createUser (@Body () createUserDto: CreateUserDto ) { }
swagger配置token为了在 Swagger UI 中显示 token 认证,需要在 app.module.ts 中配置 SwaggerModule:
swaggerToken 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import { NestFactory } from '@nestjs/core' ;import { SwaggerModule , DocumentBuilder } from '@nestjs/swagger' ;import { AppModule } from './app.module' ;async function bootstrap ( ) { const app = await NestFactory .create (AppModule ); const options = new DocumentBuilder () .setTitle ('NestJS API' ) .setDescription ('The NestJS API description' ) .setVersion ('1.0' ) .addBearerAuth () .build (); const document = SwaggerModule .createDocument (app, options); SwaggerModule .setup ('api-docs' , app, document ); await app.listen (3000 ); } bootstrap ();
addBearerAuth() 方法用于添加 Bearer 认证,setBearerAuth() 方法用于设置认证名称和位置。
typeorm数据库映射TypeORM,这是一个强大的ORM(对象关系映射)库,用于Node.js,支持多种数据库。
安装依赖 1 pnpm install @nestjs/typeorm typeorm mysql2 --save
配置TypeORM app.module.ts中加入typeorm配置项!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { Module } from '@nestjs/common' ;import { TypeOrmModule } from '@nestjs/typeorm' ;@Module ({ imports : [ TypeOrmModule .forRoot ({ type :'mysql' , host : 'localhost' , port : 3306 , username : 'root' , password : 'root' , database : 'test' , synchronize : true , autoLoadEntities : true }), ], }) export class AppModule {}
配置项 说明 类型 type数据库类型mysql oracle sqlitehost数据库主机地址stringport数据库主机端口numberusername数据库用户名stringpassword数据库密码stringdatabase数据库名称stringentities实体文件路径string[]synchronize是否自动将实体类同步到数据库字段booleanautoLoadEntities是否自动加载实体类booleanretryAttempts连接失败重试次数numberretryDelay连接失败重试延迟number
配置实体类 user.entity.ts
定义User实体类,用于映射User表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { Column , Entity , PrimaryGeneratedColumn } from "typeorm" ;@Entity ()export class User { @PrimaryGeneratedColumn () id : string ; @Column () username : string ; @Column () password : string ; @Column () tel : string ; @Column () email : string ; @Column () address : string ; }
装饰器 描述 @Entity()定义实体类 @PrimaryGeneratedColumn()定义主键,并设置自增 @Column()定义字段,并设置类型
注册实体类模块 在user.modules.ts模块中通过TypeOrmModule.forFeature([User]) 来进行注册!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import { Module } from '@nestjs/common' ;import { UserService } from './user.service' ;import { UserController } from './user.controller' ;import { User } from './entities/user.entity' ;import { TypeOrmModule } from '@nestjs/typeorm' ;@Module ({ imports : [TypeOrmModule .forFeature ([User ])], controllers : [UserController ], providers : [UserService ,{ provide : 'customService' , useClass : UserService }], }) export class UserModule {}
TypeOrm装饰器Entity()用于定义实体类,并设置表名。
1 2 3 4 @Entity ({ name : 'users' })export class User { }
PrimaryGeneratedColumn()用于定义主键,并设置自增。
1 2 3 4 5 6 @PrimaryGeneratedColumn ()id : string ;@PrimaryGeneratedColumn ('uuid' )id : string ;
Column()用于定义字段,并设置类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Column ({ type : 'varchar' , length : 50 })username : string ;@Column ('simple-array' )names : string [];@Column ({ type : 'enum' , enum : ['male' , 'female' ] })gender : string ;@Column ('simple-array' )meta : object ;@Column ({ type : 'decimal' , precision : 10 , scale : 2 })price : number ;
Column({})配置项
配置项 说明 类型 type字段类型string number boolean date json enumlength字段长度numberprecision字段精度numberscale字段小数位数numberdefault字段默认值string number boolean date json enumnullable是否可为空booleanunique是否唯一booleancomment字段注释stringenum枚举类型any[]generated是否生成string uuid incrementname字段名称stringupdate是否更新booleanprimary是否主键booleanunique是否唯一booleanselect是否查询(为true时,返回结果将会过滤该字段)booleaninsert是否插入booleanupdate是否更新booleandelete是否删除booleandefault默认值string number boolean date json enum
Index()用于定义索引。
1 @Index ('idx_user_username' , ['username' ], { unique : true })
Generated()用于定义生成器。
1 2 Generated ('uuid' )uuid : string ;
CreateDateColumn()用于定义创建时间字段。
1 2 @CreateDateColumn ()created_at : Date ;
UpdateDateColumn()用于定义更新时间字段。
1 2 @UpdateDateColumn ()updated_at : Date ;
ManyToOne()用于定义一对多关系。
1 2 @ManyToOne (() => User , (user ) => user.posts )user : User ;
OneToMany()用于定义一对多关系。
1 2 @OneToMany (() => Post , (post ) => post.user )posts : Post [];
ManyToMany()用于定义多对多关系。
1 2 @ManyToMany (() => Tag , (tag ) => tag.posts )tags : Tag [];
JoinTable()用于定义多对多关系的中间表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @ManyToMany (() => Tag , { joinTable : { name : 'post_tag' , joinColumn : { name : 'post_id' , referencedColumnName : 'id' , }, inverseJoinColumn : { name : 'tag_id' , referencedColumnName : 'id' , }, }, }) tags : Tag [];