Fork me on GitHub

nestjs入门学习总结(一):控制器、服务、模块

  • 为什么要用nestjs,和egg区别对比
  • nest项目初始化,了解目录结构
  • nest cli命令了解
  • nest基础知识点学习:控制器、服务、模块

为什么要用nestjs,和egg区别对比

官网介绍

  1. Nest提供了一种开箱即用的应用程序架构,允许开发人员和团队创建高度可测试、可扩展、松耦合和易于维护的应用程序。

  2. Nest (NestJS)是一个用于构建高效、可扩展的Node.js服务器端应用程序的框架。它使用渐进式JavaScript,构建并完全支持TypeScript(但仍然允许开发人员使用纯JavaScript编写代码),并结合了OOP(面向对象编程),FP(函数式编程)和FRP(函数式响应式编程)的元素。

  3. 在底层,Nest使用了健壮的HTTP服务器框架,比如Express(默认的),也可以选择配置为使用fasttify !

  4. Nest在这些常见的Node.js框架(Express/ fasttify)之上提供了一个抽象层次,但也直接向开发人员公开了它们的api。这使得开发人员可以自由地使用底层平台可用的无数第三方模块。

NestJS和Egg.js的区别以及对比

1、Egg.js是和Nest.js 都是为企业级框架和应用而生。
2、 Egg.js和Nest.js都是非常优秀的Nodejs框架。Egg.js基于Koa,Nest.js默认基于Express,nest也可以基于其他框架
3、 Egg.js文档相比Nestjs优秀很多
4、 Express、Koa 是 Node.js 社区广泛使用的框架,简单且扩展性强,非常适合做个人项目。但框架本身缺少约定,标准的 MVC 模型会有各种千奇百怪的写法。Egg 和Nestjs都是按照约定进行开发的。但是Egg相比Nestjs约定更标准。
5、 面向对象方面Nestjs优于Egg.js,Nestjs基于TypeScript, 如果你会angular或者java学习Nestjs非常容易。

Nestjs的特性:

  • 依赖注入容器
  • 模块化封装
  • 可测试性
  • 内置支持 TypeScript
  • 可基于Express或者fastify

Egg.js的特性:

  • 提供基于 Egg 定制上层框架的能力
  • 高度可扩展的插件机制
  • 内置多进程管理
  • 基于 Koa 开发,性能优异
  • 框架稳定,测试覆盖率高
  • 渐进式开发

nest项目初始化,了解目录结构

全局安装cli
npm install -g @nestjs/cli

初始化创建项目
nest new my-nest-project

项目启动
yarn run start:dev

浏览器访问
http://localhost:3000/

目录结构了解

命令生成一个cats模块

nest g module cats
src
├──cats // 模块文件
│    ├──dto
│    │   └──create-cat.dto.ts  // 数据传输对象
│    ├──interfaces
│    │     └──cat.interface.ts  // 定义实体对象
│    ├─cats.service.ts  // 服务层,逻辑处理及数据获取
│    ├─cats.controller.ts  // 控制器负责处理传入的请求和向客户端返回响应。
│    └──cats.module.ts   // 用于组织应用程序结构
├──app.module.ts   // 根模块,组织模块结构
└──main.ts  // 应用程序入口文件,创建应用实例

nest cli命令了解

更多命令查看 nest generate --help、nest --help

全局安装cli工具
npm install -g @nestjs/cli

创建项目
nest new my-nest-project

生成模块
nest g module cats

生成控制器
nest g controller cats

生成服务
nest g service cats

生成过滤器
nest g filter http-exception

生成拦截器
nest g interceptor transform

生成一个CRUD的功能模块
nest g resource user

更多生成命令参考查看:https://docs.nestjs.com/cli/usages

创建顺序:先创建模块,这样后面创建的控制器和服务类就会自动注册到模块中

nest基础知识点学习:控制器、服务、模块

控制器

控制器负责处理传入的请求和向客户端返回响应。

  1. 路由
使用 @Controller() 装饰器定义一个基本的控制器。可选 路由路径前缀设置为 cats。在 @Controller() 装饰器中使用路径前缀可以使我们轻松地对一组相关的路由进行分组,并最大程度地减少重复代码。

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}
  1. Request

在处理函数的签名中使用 @Req() 装饰器,指示 Nest 将请求对象注入处理程序。

findAll(@Req() request: Request): string {
    return 'This action returns all cats';
  }

Request 对象代表 HTTP 请求,并具有查询字符串,请求参数参数,HTTP 标头(HTTP header) 和 正文(HTTP body)的属性

可以使用专用的装饰器,比如开箱即用的 @Body() 或 @Query()

@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

在请求处理函数中注入 @Res()或 @Response() 时,必须通过调用 response 对象(例如,res.json(…) 或 res.send(…))发出某种响应,否则 HTTP 服务器将挂起

  1. 资源

Nest 为所有标准的 HTTP 方法提供了相应的装饰器:@Put()、@Delete()、@Patch()、@Options()、以及 @Head()。此外,@All() 则用于定义一个用于处理所有 HTTP 请求方法的处理程序。

@Controller('cats')
export class CatsController {
  @Post()
  create(): string {
    return 'This action adds a new cat';
  }

  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}
  1. 状态码

响应的状态码总是默认为 200,除了 POST 请求(默认响应状态码为 201),我们可以通过在处理函数外添加 @HttpCode(...) 装饰器来轻松更改此行为。

@Post()
@HttpCode(204)
create() {
  return 'This action adds a new cat';
}
  1. Headers
    指定自定义响应头,可以使用 @header() 装饰器或类库特有的响应对象
@Post()
@Header('Cache-Control', 'none')
create() {
  return 'This action adds a new cat';
}
  1. 路由参数

接受动态数据(dynamic data)作为请求的一部分时(例如,使用GET /cats/1 来获取 id 为 1 的 cat)

路由参数可以使用 @Param() 装饰器访问,该装饰器应添加到函数签名中。

@Get(':id')
findOne(@Param() params): string {
  console.log(params.id);
  return `This action returns a #${params.id} cat`;
}

还可以将特定的参数标记传递给装饰器,然后在方法主体中按参数名称直接引用路由参数。

@Get(':id')
findOne(@Param('id') id): string {
  return `This action returns a #${id} cat`;
}
  1. 请求负载

POST 路由处理程序样例中,处理程序没有接受任何客户端参数。我们在这里通过添加 @Body() 参数来解决这个问题

我们需要确定 DTO(数据传输对象)模式。DTO是一个对象,它定义了如何通过网络发送数据。我们可以通过使用 TypeScript 接口(Interface)或简单的类(Class)来定义 DTO 模式。

创建 CreateCatDto 类:

/*
  create-cat.dto.ts
*/
export class CreateCatDto {
  readonly name: string;
  readonly age: number;
  readonly breed: string;
}

使用新创建的DTO:

@Post()
async create(@Body() createCatDto: CreateCatDto) {
  return 'This action adds a new cat';
}
  1. 最后

控制器总是属于模块,这就是为什么我们在 @Module() 装饰器中包含 controllers 数组的原因。

使用 @Module() 装饰器将元数据附加到模块类中,现在,Nest 可以轻松反射(reflect)出哪些控制器(controller)必须被安装。

import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';

@Module({
  controllers: [CatsController],
})
export class AppModule {}

Providers提供者

Providers 是 Nest 的一个基本概念。许多基本的 Nest 类可能被视为 provider - service, repository, factory, helper 等等。 他们都可以通过 constructor 注入依赖关系。
Provider 只是一个用 @Injectable() 装饰器注释的类。

  1. service服务
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';

@Injectable()
export class CatsService {
  private readonly cats: Cat[] = [];

  create(cat: Cat) {
    this.cats.push(cat);
  }

  findAll(): Cat[] {
    return this.cats;
  }
}

Cat 接口

// interfaces/cat.interface.ts

export interface Cat {
  name: string;
  age: number;
  breed: string;
}

在 CatsController 里使用它,CatsService 是通过类构造函数注入的

import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';

@Controller('cats')
export class CatsController {
  constructor(private catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}
  1. 注册提供者

定义了提供者(CatsService),并且已经有了该服务的使用者(CatsController),我们需要在 Nest 中注册该服务,以便它可以执行注入

编辑模块文件(app.module.ts),然后将服务添加到@Module()装饰器的 providers 数组中。

// app.module.ts

import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class AppModule {}

模块

模块是具有 @Module() 装饰器的类。 @Module() 装饰器提供了元数据,Nest 用它来组织应用程序结构。

每个 Nest 应用程序至少有一个模块,即根模块。大多数情况下,您将拥有多个模块,每个模块都有一组紧密相关的功能。

@module() 装饰器接受一个描述模块属性的对象:

providers 由 Nest 注入器实例化的提供者,并且可以至少在整个模块中共享
controllers 必须创建的一组控制器
imports 导入模块的列表,这些模块导出了此模块中所需提供者
exports 由本模块提供并应在其他模块中可用的提供者的子集。
  1. 功能模块

对应同类型的功能,将它们移动到一个功能模块下

// cats/cats.module.ts

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

导入功能模块

将这个模块导入根模块 (ApplicationModule)

// app.module.ts

import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class ApplicationModule {}

模块目录结构

src
├──cats
│    ├──dto
│    │   └──create-cat.dto.ts
│    ├──interfaces
│    │     └──cat.interface.ts
│    ├─cats.service.ts
│    ├─cats.controller.ts
│    └──cats.module.ts
├──app.module.ts
└──main.ts
  1. 共享模块

实际上,每个模块都是一个共享模块。一旦创建就能被任意模块重复使用。
假设我们将在几个模块之间共享 CatsService 实例。 我们需要把 CatsService 放到 exports 数组中

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService]
})
export class CatsModule {}

每个导入 CatsModule 的模块都可以访问 CatsService ,并且它们将共享相同的 CatsService 实例。

  1. 全局模块

有时候,你可能只想提供一组随时可用的东西 - 例如:helper,数据库连接等等

import { Module, Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Global()
@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService],
})
export class CatsModule {}

@Global 装饰器使模块成为全局作用域。 全局模块应该只注册一次,最好由根或核心模块注册。 在上面的例子中,CatsService 组件将无处不在,而想要使用 CatsService 的模块则不需要在 imports 数组中导入 CatsModule。

项目源码

代码已经上传到github中,欢迎大家star,持续更新,如有任何问题可以联系我v:sky201208(注明来意)

https://github.com/fozero/cloud-collect-nestjs

参考阅读

关于我&前端&node进阶交流学习群

大家好,我是阿健Kerry,一个有趣且乐于分享的人,前小鹏汽车、货拉拉高级前端工程师,长期专注前端开发,如果你对前端&Node.js 学习进阶感兴趣的话(后续有计划也可以),可以关注我,加我微信【sky201208】,拉你进交流群一起交流、学习共同进步,群内氛围特别好,定期会组织技术分享~

posted @ 2023-07-12 20:43  fozero  阅读(432)  评论(0编辑  收藏  举报