一篇文章学会使用 NestJS 的 Module 实现高效的代码模块管理

前言

在构建大型Web应用时,代码的组织和管理往往十分复杂。有没有一种方式可以使应用的每一个部分可以过分承担工作并保持独立,同时又能一起协作实现应用的完整功能呢?

本文将为您详细介绍NestJS模块的概念以及创建过程。NestJS模块类似于工厂中的各个部门,每个部门有一套自己的工作模式,但最终共同完成整个生产流程。通过这篇文章,您不仅将理解NestJS模块是什么,更能掌握如何创建自己的自定义模块,使你的NestJS应用更加强大和易于管理。

什么是 NestJS Module 模块

如果你设想一个大型工厂,各部门按照自己的功能运作,而NestJS模块就相当于这里的“部门”。具体来说,NestJS 模块(Module)是一个以类(Class)为单位,组织和封装功能模块的方式。每个部门(模块)有一组协同工作的员工(控制器、供应者等),他们协助工厂(应用程序)实现特定的功能。

Module 模块组成部分

模块使用 @Module() 装饰器进行标注,接受一个描述如何组织应用的元数据对象,主要由以下四部分组成:

  • providers:这些是应用中的“职员”们,会被Nest实例化,他们在整个应用中都可以被使用。
  • controllers:这些是工厂的“管理员”们,定义了一组路由实例,可以处理进出工厂的“通行证”(HTTP请求)。
  • imports:这表示工厂部门(模块)所依赖的其他部门(模块)。
  • exports:这是一个可以被其他部门(模块)使用的职员(供应者)列表。

创建自定义 Module 模块

一、简单模块 Module

以下是创建自定义NestJS模块的步骤:

  1. 新建类并添加装饰器

    使用 @Module() 装饰器标注自定义模块类。

    typescript
    import {Module} from '@nestjs/common'; @Module({}) export class CustomModule {}
  2. 填写元数据对象

    @Module() 装饰器的元数据对象中定义模块的 providerscontrollersimportsexports

    typescript
    import { Module, Controller, Get } from '@nestjs/common'; @Controller('custom') class CustomController { @Get() getHello() { return 'Hello from custom module'; } } @Module({ imports: [], // 其他需要的模块列表 controllers: [CustomController], // 定义的控制器列表 providers: [], // 定义供应者(provider)的列表 }) export class CustomModule {}

    在这个例子中,我们创建了一个自定义模块,当访问 '/custom' 路径时,会返回 'Hello from custom module'。

二、复杂模块 Module

下面将创建一个自定义模块,包含服务(Service),控制器(Controller)和一个模块间的引用(Import)。

想象我们正在创建一个用户APP,下面我们将创建一个 'UserModule',这个模块将导入 'DatabaseModule',并使用 'UserService' 来完成用户相关的操作。

typescript
import { Module } from '@nestjs/common'; import { UserController } from './user.controller'; import { UserService } from './user.service'; import { DatabaseModule } from '../database/database.module'; @Module({ imports: [DatabaseModule], // 导入DatabaseModule controllers: [UserController], // 定义UserController providers: [UserService], // 定义UserService exports: [UserService], // 导出UserService,让其他模块可以使用 }) export class UserModule {}

在这个模块中,我们定义了:

  • DatabaseModule: 这是我们应用程序中管理数据库操作的模块。
  • UserController: 这个控制器处理所有的用户请求。
  • UserService: 这个服务完成所有与用户相关的任务,包括从数据库读取用户数据等。

现在,我们假设 DatabaseModuleUserControllerUserService已经被正确定义,这样我们 UserModule 就可以正常工作。

三、动态模块 Module

更进一步创建一个动态模块,可以接收配置并基于此配置来决定模块的行为。这种情况在实际开发中经常出现,例如连接数据库,每个应用可能需要不同的数据库配置信息。这就需要我们创建 forRoot 方法在模块中接收这些配置。

首先,让我们创建 DatabaseModule,这个模块将接收一些配置参数,然后根据这些参数创建数据库连接。

typescript
import { Module, DynamicModule } from '@nestjs/common'; import { createDatabaseProviders } from './database.providers'; import { ConnectionOptions } from 'typeorm'; @Module({}) export class DatabaseModule { static forRoot(options: ConnectionOptions): DynamicModule { const providers = createDatabaseProviders(options); return { module: DatabaseModule, providers: providers, exports: providers, }; } }

函数 createDatabaseProviders 根据接收的 options 参数(主要是数据库链接的配置信息)恰当地创建和配置提供者。

我们的 UserModule 现在就可以导入 DatabaseModule 并提供数据库配置:

typescript
import { Module } from '@nestjs/common'; import { UserController } from './user.controller'; import { UserService } from './user.service'; import { DatabaseModule } from '../database/database.module'; @Module({ imports: [ DatabaseModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'test', password: 'test', database: 'test', entities: [], synchronize: true, }), ], controllers: [UserController], providers: [UserService], exports: [UserService], }) export class UserModule {}

这是NestJS中动态模块的一个基本使用示例。通过这种方式,我们可以灵活地为模块提供配置,大大增强了模块的可复用性和扩展性。

总结

NestJS的模块系统为你提供了一种组织代码的优雅方式,让代码结构清晰且易于维护。希望通过本篇文章,你能明白何为NestJS模块,以及如何创建自定义模块。现在,你可以开始动手实践,创建属于自己的模块,让你的应用程序变得更加鲁棒。