Nest 是一个NodeJS服务端框架。区别于 Express/Koa/Fastify 没有(弱)主张的、纯粹提供HTTP服务器封装和异步流程串并行的思路的基础框架,NestJS提供架构主张,有自己一套架构模式,开发者需要按照NestJS要求的架构来组织代码。适合团队用于构建高效、可靠的、高可拓展、松散耦合、易于测试的大型NodeJS服务端应用。Nest 基于 Express 或 Fastify 封装HTTP请求和路由,并支持其他 web 框架/库,并直接暴露他们的接口,使得开发者可以自由使用第三方库。Nest 使用 TypeScript 来编写程序,用了很多TS的写法如装饰器等特性,结合了 OOP、FP、FRP的相关理念,设计上很多灵感来自于 Angular 或者后端常用的Java技术栈 Spring 框架,如依赖注入、面向切面编程(AOP)等,可以说 Nest 是 Node.js 版的 Spring 框架。
Module
Nest 采用模块化思路,将 APP 分割成各个模块,可以是专属功能的模块,也可以是通用的共享模块以及全局模块。APP 至少有一个根模块,包含定义的providers、controllers,repositories, interceptors, middleware, 等等,以及imports及exports。一个模块可以引用其他模块,也可以被其他模块引用。exports 可以导出providers(service)供其他模块使用。APP 由 各 Modules 组成,Modules 又由 controller、service分层,代码组织、职责划分清晰。这种模块化的组织方式,使我们可以将整个APP按照逻辑领域分割为各个模块,降低代码之间耦合的同时增强可拓展性。可以结合Domain-Driven Development。
Controller
负责接收请求,返回响应。与路由系统配合,路由系统决定那个请求使用那个 controller,期间可以调用 service。Nest 使用 TS 的装饰器语法,将路由系统封装并提供接口,使得 controller 可以很方便的与路由系统结合,相较于 Express 等框架中心化的路由,Nest 路由是去中心化的, 而且与 controller 的结合非常方便:这其中可以对类、方法及参数都可以使用装饰器。对类使用 @Controller 装饰器将类作为一个 controller 与路由结合,对方法可以使用@Get/@Post作为请求方法处理器,对方法参数使用@Req/@Query等访问请求及请求内各部分数据。
Provider
Provider 是能够向别的类注入依赖的类,依赖可以是services, repositories, factories, helpers 等等。相当于提供服务的 service 层。Provider 是来自依赖注入的概念。
依赖注入:
模块化是分割代码的一种方式,依赖注入就是一种设计模式,用来连接模块并且管理好他们之间的依赖关系,做到模块间的高内聚低耦合。依赖注入在面向对象编程中比较常见,在面向对象编程中,引入的依赖通常是类,使用时就要创建这个类的实例去用,因此当一个类A依赖另外一个类B时,经常性的、一种不好的写法就是硬编码依赖,即类A引入类B并在A里创建B的实例来使用,然而当创建B实例的方式改变,A就不得不跟随着B改变。使用硬编码依赖,A引入的依赖越多,这种耦合就越严重。此外,依赖的实例会被重复创建。
此时可以引入一个第三方依赖管理容器,这个容器首先会包含注册的各种依赖,当A依赖B时,这个容器会找到B并实例化B,向A直接注入B的实例,A不必在内部实例化B就能直接使用B实例。这解决了硬编码依赖中的耦合及重复实例化问题,并且使各模块易于测试。
新增模块
首先理解netsJS的设计模式:主要就是 Controller 、Service、Module ,形成了一个模块
- Controller :控制器,主要作用:提供api接口,负责处理路由,中转,验证等一些简洁业务
- Service:又称为 Provider ,是一系列服务,repo,工厂方法,helper的总称。主要负责处理具体的业务,如数据库的增删改查,事务,并发等逻辑代码
- Module:负责将Controller和Service连接起来
接下来,创建模块:直接使用nest-cli创建
nest g [文件类型] [文件名] [文件目录(src目录下)]
首先创建Service,因为Controller和Module都需要引入
- Service
输入
nest g service user logical //创建sevice类型的文件,文件名:user,文件目录为:logical
打开user.service.ts,长这样
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {}
仿照最初的app.service.ts来写一个简单的业务,在user.service.ts里写:
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {
//创建方法,后续调用
findOne(username:string):string{
if(username==='Kid'){
return 'Kid is here';
}
return 'No one here';
}
}
2. Controller
创建
nest g controller user logical
然后,把Service的业务逻辑引入
import { Body, Controller, Post } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
//创建实例
constructor(private readonly usersService:UserService){}
@Post('find-one')
findOne(@Body() body:any){
return this.usersService.findOne(body.username);
}
}
使用apiPost访问:http://localhost:3000/overall-situation/user/find-one
到此就成功的匹配到了路由
注意:千万不要往Controller里面添加乱七八糟的东西,尤其不要写业务逻辑,Controller应该保持简洁,干净。
3.Module
其实学到这也挺奇怪的,上面的Service和Controller已经可以解决业务所需,那Module又是干啥的?
打开app.module.ts:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserService } from './logical/user/user.service';
import { UserController } from './logical/user/user.controller';
@Module({
imports: [],
controllers: [AppController, UserController],
providers: [AppService, UserService],
})
export class AppModule {}
发现里面已经有我们创建的UserService和UserController,这是nest-cli用指令创建文件的时候,帮我们自动引入了相关文件。而main.ts又引入了 AppModule,并且使用了 NestFactory创建了实例(翻到最上面的main.ts)
因此,如果一般模块的话,是不需要创建module的,cli帮我们操作了这一步。
但是,学习还是要学的,哈哈。
先创建文件
nest g module user logical
初始化的module长这样
然后我们把Service和Controller组装起来(有没有觉得这一步像是vue的main.js)
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
controllers:[UserController],
providers:[UserService],
exports:[UserService]
})
export class UserModule {}
那这一步的作用是啥呢?
就是其他Module想引入User的时候,就不能同时引入Service和Controller了,然后修改下app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
// import { UserService } from './logical/user/user.service';
// import { UserController } from './logical/user/user.controller';
import { UserModule } from './logical/user/user.module';
@Module({
imports: [UserModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
保存运行,发现路由依然有效
学术交流文章,不做为临床依据,特此声明。发布者:Chu,转转请注明出处:https://www.icu.cn/?p=3579