【NestJS 编程艺术】4. 探索NestJS的高效开发:一切皆module

在 NestJS 中,一切皆模块(Module)是其核心理念之一,本文将深入探讨 NestJS 中模块的原理,并通过实践代码来展示如何高效地使用模块。

【NestJS 编程艺术】3. 探索NestJS的高效开发:nest-cli的全面指南 - 掘金 (juejin.cn) 还不会应用 nest-cli的同学,可以参考上篇

模块(Module)解析

在 NestJS 中,模块(Module)是应用程序的基本构建块。每个模块都是一个独立的单元,负责管理自己的控制器(Controllers)、服务(Services)、提供者(Providers)和导入其他模块。这种模块化的设计使得代码结构清晰,便于维护和扩展。

模块的结构

一个基本的 NestJS 模块包含以下几个部分:

  1. 控制器(Controllers) :负责处理客户端请求,并将请求委托给服务层处理。
  2. 服务(Services) :包含业务逻辑,通常与数据库或其他外部服务进行交互。
  3. 提供者(Providers) :可以是服务、值(Value)或类(Class),用于在应用程序中提供特定的功能或数据。
  4. 导入(Imports) :指定当前模块所依赖的其他模块,以便使用这些模块中定义的控制器、服务和提供者。

实践代码

让我们通过一个简单的例子来实践模块的使用。在 NestJS 中创建模块非常简单。你可以使用 CLI 工具生成模块的骨架,或者手动创建模块文件。

步骤 1: 创建模块

首先,我们创建一个名为 UserModule 的模块。以下为命令行创建方式:

sql 复制代码
nest g module user

以下为生成的 user.module.ts 文件:

kotlin 复制代码
// user.module.ts
@Module({
  providers: [UserService],
  controllers: [UserController],
})
export class UserModule {}

命令行的好处是可以自动将 UserModule 加入 app.module.tsimports 数组中,如下:

less 复制代码
// app.module.ts
@Module({
  imports: [UserModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }

步骤 2: 定义控制器

控制器负责处理客户端请求,并将请求委托给服务层(步骤3要创建的UserService)处理。 以下为命令行生成一个用户控制器 UserController

sql 复制代码
nest g controller user

生成后的代码如下:

less 复制代码
// user.controller.ts
@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  findAll() {
    return this.userService.findAllUsers();
  }
}

步骤 3: 定义服务

通常我们的业务逻辑都写在service层,进行数据库增删改查的逻辑操作或其他外部服务进行交互。 然后,我们创建一个 UserService 服务,它将包含业务逻辑。

sql 复制代码
nest g service user
kotlin 复制代码
// user.service.ts
@Injectable()
export class UserService {
  findAllUsers(): string[] {
    // 这里可以是数据库查询或其他业务逻辑,可以通过 ORM 工具进行查询数据库的操作,并返回 User 列表;
    // 下一篇会介绍 TypeORM 的接入
    return ['User1', 'User2', 'User3'];
  }
}

以上为 Module 的概览;NestJS 中的模块概念还包括全局模块共享模块动态模块,这些模块类型提供了更高级的模块化和代码复用策略。下面我们将对这些概念进行补充说明。

全局模块

全局模块是一种特殊的模块,它的作用域是全局的。这意味着在全局模块中定义的控制器、服务和提供者可以被应用程序中的任何其他模块访问,而无需显式地导入它们。全局模块通常用于那些在多个地方被频繁使用的功能。

创建一个全局模块可以通过在 @Module() 装饰器中使用 global: true 选项来实现。

kotlin 复制代码
// user.module.ts
@Module({
  global: true,
  providers: [UserService],
})
export class UserModule {}

在这个例子中,UserService 将在整个应用程序中可用,无需在每个使用它的模块中导入 UserModule。 比如有一个 OrderModule 需要用到 UserService 提供的能力,就可以很方面的进行使用:

less 复制代码
@Controller()
export class OrderController {
  constructor(private readonly userService: UserService) {}

  @Get()
  getHello(): string {
    return this.userService.getUsers();
  }
}

共享模块

共享模块是一种可以在多个子模块中共享的模块。共享模块的目的是为了避免模块间的重复导入,从而减少模块间的耦合。当你有一个模块被多个其他模块共同依赖时,可以将这个模块设置为共享模块。

共享模块的创建与普通模块相同,但需要在导入时使用 SharedModule

kotlin 复制代码
// shared.module.ts
@Module({
  imports: [DatabaseModule],
  exports: [DatabaseModule],
})
export class SharedModule {}

在这个例子中,DatabaseModule 被导入到 SharedModule 并被导出,这样任何导入 SharedModule 的模块都会间接导入 DatabaseModule

动态模块

动态模块允许你在运行时动态地加载和卸载模块。这种模块特别适用于需要根据应用程序状态或用户请求来改变应用程序行为的场景。动态模块可以通过 DynamicModule 装饰器来创建。

kotlin 复制代码
// dynamic.module.ts
@Module({
  // 动态加载的配置项可以在这里定义
})
export class DynamicModule {}

动态模块通常与 forRootforFeature 方法结合使用,这些方法可以在应用程序的不同生命周期阶段加载模块。

kotlin 复制代码
// app.module.ts
import { DynamicModule } from '@nestjs/common';

@Module({
  imports: [
    SomeModule.forRootAsync({
      useFactory: () => new DynamicModule(),
    }),
  ],
})
export class AppModule {}

在这个例子中,SomeModule 使用 forRootAsync 方法异步加载 DynamicModule

总结

全局模块、共享模块和动态模块为 NestJS 应用程序提供了更灵活的模块化策略。全局模块适用于全局共享的服务和控制器,共享模块用于减少模块间的耦合,而动态模块则允许在运行时动态地加载和卸载模块。这些高级模块类型可以帮助你构建更加灵活和可维护的 NestJS 应用程序。

相关推荐
AI大模型-小华25 分钟前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子3 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅3 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni3 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学4 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端
赵庆明老师5 小时前
Vben精讲:21-详解web-antd:tsconfig.json
前端·json·vim
wc885 小时前
微软EDGE浏览器功能学习
前端·学习·edge
Csvn5 小时前
🎯 原生 `<dialog>` 元素:终于可以扔掉一半的自定义弹窗组件了?
前端
Csvn5 小时前
🎨 CSS @layer:用「层叠优先级」终结样式打架的世纪难题
前端