NestJS入门controller、DTO、providers、module。
官方API地址https://docs.nestjs.com/
Nest(或NestJS)是一个用于构建高效,可扩展的Node.js服务器端应用程序的框架。也可以在Nest中使用express框架的扩展
安装(官方也有推荐)
npm i -g @nestjs/cli //全局安装脚手架
nest new project-name //使用脚手架创建nest项目
脚手架创建的项目自带:@nestjs/core @nestjs/common rxjs reflect-metadata这些依赖
项目目录:src下面的主要文件
xxx.controller.ts 是一个nest的路由控制器
xxx.controller.spec.ts 是一个控制器测试文件
xxx.service.ts 对应的服务,把控制器的一些实现过程的抽离,让controller文件不会太过臃肿,也减少了耦合度
xxx.module.ts 是把控制器,服务等注册成一个应用程序的模块文件
main.ts 主要文件,是程序的主入口,也是启动整个项目的主文件,可以和express那样配置中间件等操作,使用核心功能NestFactory创建Nest应用程序实例的应用程序的条目文件。
1.控制器 (路由控制器)
用装饰器书写后端路由
@Controller() // 装饰一个类,把类注册成路由控制器,可以传递字符串路由参数或者路由表达式等
例如: @Controller(‘user’) => 每次请求内部路由方法:localhost:3000/user …
Get, Post, Put, Delete, Patch等装饰器修饰类的方法,把方法注册成每一个路由,分别是get、post、put、delete、patch请求等
// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller('user') //(注册路由必选装饰器),传入一个可选参数,可以让类内部所有的路由加上这个参数,/user user 看习惯一个样
export class AppController {
// constructor构造函数创建之后,会在providers中找到对应的被Injectable修饰的类,注入到这里
constructor(private readonly appService: AppService) { } // Nest是围绕通常称为依赖注入的强大设计模式构建的,类型解析
@Get() // 把这个类方法注册成一个get路由
public getHello(): string {
return 'Hello World';
}
}
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
controllers: [AppController], // 在此模块中定义的控制器集,必须进行实例化
providers: [AppService], // 注册服务成一个提供者,提供给controller使用
})
export class AppModule { }
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
async function bootstrap() {
// const app = await NestFactory.create<NestExpressApplication>(AppModule); // 使用express
// 设置全局前缀
// app.setGlobalPrefix('/api');
const app = await NestFactory.create(AppModule); // 默认使用
await app.listen(3000);
}
bootstrap();
设置全局前缀 app.setGlobalPrefix(’/api’); //然后整个API请求都需要加上/api
这时候用get请求访问http://localhost:3000/user就会返回一个字符串 'Hello World'
这时候用get请求访问http://localhost:3000/user就会返回一个字符串 'Hello World'
Get, Post, Put, Delete, Patch等装饰器也可以传递字符串参数或者一些正则表达式
//方式1 匹配/
@Get()
//方式2 匹配/get
@Get('get') // or @Get('/get')
//方式3 匹配/get/字符串id
@Get('get/:id')
//方式4 匹配/user/任意字符
@Get('user/*')
Post, Put, Delete, Patch等装饰器也是一样的用法,以及类装饰器Controller也是可以这样写
Post, Put, Delete, Patch等装饰器也是一样的用法,以及类装饰器Controller也是可以这样写
当getHello方法的逻辑操作过于频繁的情况下,可以抽离出来,写到service服务层上面,让逻辑更加清晰,耦合度降低
//app.service.ts
import { Injectable } from '@nestjs/common';
/**
* 控制器应处理HTTP请求并将更复杂的任务委派给提供者。提供程序是纯类JavaScript类,在@Injectable()类声明之前有一个装饰器。
* * Injectable装饰器,控制反转(“IoC”)容器
*/
@Injectable() // 控制反转(“IoC”)容器
export class AppService<T = any> {
public getHello(): string {
return 'Hello World!';
}
}
服务层 使用Injectable装饰器装饰,让module模块层的providers能够扫描到这个服务层,用于controller层的注入,使得抽离出的部分写在service层
这时候的app.controller.ts
这时候的app.controller.ts
// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller('user') //(注册路由必选装饰器),传入一个可选参数,可以让类内部所有的路由加上这个参数,/user user 看习惯一个样
export class AppController {
// constructor构造函数创建之后,会在providers中找到对应的被Injectable修饰的类,注入到这里
constructor(private readonly appService: AppService) { } // Nest是围绕通常称为依赖注入的强大设计模式构建的,类型解析
@Get() // 把这个类方法注册成一个get路由
public getHello(): string {
return this.appService.getHello();
}
}
这样的结果也是一致的.
其它:
当你需要接收前端传递过来的参数,获取请求头、获取session、request、response、next的时候,可以使用形参装饰器
// app.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { AppService } from './app.service';
@Controller('user') //(注册路由必选装饰器),传入一个可选参数,可以让类内部所有的路由加上这个参数,/user user 看习惯一个样
export class AppController {
// constructor构造函数创建之后,会在providers中找到对应的被Injectable修饰的类,注入到这里
constructor(private readonly appService: AppService) { } // Nest是围绕通常称为依赖注入的强大设计模式构建的,类型解析
@Get() // 把这个类方法注册成一个get路由
public getHello(): string {
return this.appService.getHello();
}
@Post('/body')//获取body里面的name参数并返回
public getBody(@Body('name') name: string): string {
return name;
}
}
@Body(‘name’) //获取整个body对象的name属性的值
@Body() //则表示获取整个body对象
Param、Headers、Query、Session等用法一致
还有一些装饰器:
HttpCode:成功返回的status 默认是200
Redirect:请求重定向,让这个请求结果重定向到Redirect的那个uri
Next, Res, Req就是express的三剑客了,相信都知道的了,用这三个装饰变量,即可获得对应的属性
@HttpCode(202) // 让成功的响应从默认值200变成202
@Get('test')
public test(@Req() request: Request, @Res() response: Response, @Next() next: (url?: string) => void): string {
// next('/url');
// next();
return 'test';
}
2.DTO 数据传输对象(架构) 用于存放传输的数据,例如获取的数据对象、返回的数据对象
// body.dto.ts
export class CreateBodyDto {
public readonly username: string;
public readonly password: string;
}
创建一个body dto,用于接收整个body
// app.controller.ts 补充
import { CreateBodyDto } from './DTO/body.dto';
@Post('/body')
public validate(@Body() body: CreateBodyDto): CreateBodyDto {
return body;
}
当然@Body() body: any 也是可以的,但是这样违背了ts的强类型语言的特点,同时也降低了代码的复用性等,让代码的可读性更差,使用DTO类来修饰接收或者返回的参数的情况下,可以有更友好的提示和复用性等。
dto:主要用于数据传输对象,就是接收对象或者返回的对象,都可以,使用也较为简单
3.providers
被Injectable装饰器修饰的类就是一个服务,服务可以0个,也可以多个,然后注册在module的providers中,提供给controller等使用
@Module({
controllers: [AppController], // 在此模块中定义的控制器集,必须进行实例化,可以多个,一个控制器数组
providers:[appService,pageService...] // 一个服务的数组
})
export class AppModule { }
可选服务
import { Injectable, Optional, Inject } from '@nestjs/common';
/**
* 控制器应处理HTTP请求并将更复杂的任务委派给提供者。提供程序是纯类JavaScript类,在@Injectable()类声明之前有一个装饰器。
* * Injectable装饰器,控制反转(“IoC”)容器
*/
@Injectable() // 控制反转(“IoC”)容器
export class AppService<T = any> {
public getHello(): string {
return 'Hello World!';
}
// Inject 注入:可以基于构造函数的注入,也可以是基于属性的注入
// Optional 可选的 加上这个注解最后,表示这个参数的注入是可以选的
@Optional()
@Inject('HTTP_OPTIONS') // Identification:标识/token:令牌 提供一个唯一的标识,防止重复
private readonly course: T;
}
Optional, Inject 装饰属性,可以告诉nest,这是可选的一个选项,同时也是可以注入的选项,这些注入是nest自动注入的,我们可以在相应的情况下调用这些。
4.module 模块是用@Module()装饰器注释的类。
每个应用程序至少有一个模块,一个根模块。@Module()接收一个对象,参数如下:
- providers 将由Nest注入器实例化的提供程序,并且至少可以在此模块中共享
- controllers 在此模块中定义的控制器集,必须进行实例化
- imports 导出此模块中所需的提供程序的导入模块列表
- exports 其子集providers由此模块提供,并且应该在导入此模块的其他模块中可用
而我们上面的例子就用到了providers、controllers两个接收数组的属性
当我们需要对模块进行拆分的时候,可以使用imports接收一个模块数组
// child.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
controllers: [AppController], // 在此模块中定义的控制器集,必须进行实例化
providers: [AppService],
exports: [AppService],
})
// 实现NestModule接口,从而配置中间件
export class ChildModule implements NestModule { }
每个模块都自动成为共享模块。一旦创建,它可以被任何模块重用。
我们想要共享AppService服务的实例给其它模块使用,为了做到这一点,我们需要导出providers里面的服务,提供给其他模块使用
改造app.module.ts
import { Module } from '@nestjs/common';
// import { AppController } from './app.controller';
// import { AppService } from './app.service';
import { ChildModule } from './child.module';
@Module({
imports: [ChildModule], // 导出此模块中所需的提供程序的导入模块列表,就是把module模块划分成一个个子模块,然后导入到这个模块当中
// controllers: [AppController], // 在此模块中定义的控制器集,必须进行实例化
// providers: [AppService], // 注册服务成一个提供者,提供给controller使用
})
export class AppModule { }
exports 也可以用于模块重新导出,让此模块给其他模块使用,而不是直接给主模块.
模块类也可以注入提供者(例如,用于
配置
目的)
import { Global, Module } from '@nestjs/common';
@Global()
@Module({
//...
})
export class AppModule {
constructor(private readonly catsService: CatsService) {}
}
@Global()装饰模块后这个模块就是全局模块,全局模块只应注册一次,通常由根模块或核心模块注册。
动态模块,此功能使您可以轻松创建可自定义的模块
// database.module.ts
import { Module, DynamicModule } from '@nestjs/common';
@Module({})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule { // forRoot()方法可以同步或异步(即通过a Promise)返回动态模块。
return {
module: DatabaseModule, // 模块就是自己这个类
providers: entities, //返回的模块
// exports: entities, //导出的模块 exports的子集就是providers
};
}
}
forRoot()方法可以同步或异步(即通过a Promise)返回动态模块
动态模块的使用
import { Module } from '@nestjs/common';
import { ChildModule } from './child.module';
import { DatabaseModule } from './database.module';
@Module({
imports: [DatabaseModule.forRoot([ChildModule])],
exports: [DatabaseModule],
})
export class AppModule {}
觉得不错就收个藏什么的,谢谢
先介绍一下nest的基本控制器使用、DTO、provider、module的使用,下节介绍中间件middleware、异常过滤器exceptionFilter、管道pipe的使用
先介绍一下nest的基本控制器使用、DTO、provider、module的使用,下节介绍中间件middleware、异常过滤器exceptionFilter、管道pipe的使用
其它博客:
其它博客:
routing-controllers、class-validator、typedi的使用总结(express使用类似nest控制器的装饰器写法等)
Type-GraphQL结合装饰器写法的node框架的学习笔记
等等等…