{T}

NestJS模块化架构

一、模块化概念

1.1 什么是模块化

概念说明

模块化是 NestJS 组织应用的核心方式。所有的功能块都用模块来组织,类似于前端的组件化概念,但颗粒度更大。y'y

前端类比理解

code
前端组件化 vs 后端模块化:

前端组件化:
│
├──  组件(Component)
│   ├── 颗粒度:小(按钮、表单、列表)
│   ├── 作用:UI 层面的复用
│   └── 组织:组合成页面
│
└──  目的
    └── 减少 UI 重复代码

后端模块化:
│
├──  模块(Module)
│   ├── 颗粒度:大(用户模块、订单模块)
│   ├── 作用:功能层面的组织
│   └── 组织:组合成应用
│
└──  目的
    └── 减少业务重复代码

类比理解:
• 模块 ≈ 组件(但颗粒度更大)
• 模块组合 ≈ 组件组合
• 都是为了复用和解耦

1.2 积木类比理解

形象理解

code
积木类比:

单个积木:
│
├──  特点
│   ├── 独立存在
│   ├── 有特定形状和功能
│   └── 可单独使用
│
└──  对应
    └── 单个模块(如用户模块)

组合积木:
│
├──  特点
│   ├── 多个积木有机组合
│   ├── 形成更大的结构
│   └── 分开独立,组合成整体
│
└──  对应
    └── 整个应用(多个模块组合)

核心理念:
• 分开:各自独立
• 组合:浑然一体
• 目的:减少重复、提升可维护性

二、NestJS 模块组织结构

2.1 模块依赖关系图

官方示例图解

code
NestJS 模块组织结构:

┌─────────────────────────────────────────────────────────┐
│              Application Module(根模块)                │
│                      AppModule                           │
└───────────┬─────────────────────┬───────────────────────┘
            │                     │
    ┌───────┴───────┐     ┌───────┴───────┐     ┌──────────┐
    │  Users Module │     │ Orders Module │     │ Chat Msg │
    │   用户模块     │     │   订单模块     │     │  消息模块 │
    └───────────────┘     └───────┬───────┘     └──────────┘
                                  │
                    ┌─────────────┼─────────────┐
                    │             │             │
            ┌───────┴───────┐ ┌───┴────┐   ┌────┴─────┐
            │ Feature1 Mdl  │ │Feature2│   │Feature 3 │
            │   功能一模块   │ │ 功能二  │   │  功能三  │
            └───────────────┘ └────────┘   └──────────┘

依赖关系说明:
│
├── 一级模块
│   ├── Users Module(用户模块)
│   ├── Orders Module(订单模块)
│   └── Chat Message Module(消息模块)
│
├── 二级模块
│   ├── Feature1 Module(功能一模块)← Orders Module 依赖
│   ├── Feature2 Module(功能二模块)← Orders Module 依赖
│   └── Feature3 Module(功能三模块)← Chat Module 依赖
│
└── 依赖方向
    └── 箭头方向 = import 方向

2.2 模块导入导出关系

ES6 类比

typescript
// ========== ES6 模块导入导出 ==========

// module-a.ts
export const serviceA = { /* ... */ };

// module-b.ts
import { serviceA } from './module-a';
export const serviceB = { /* ... */ };

// ========== NestJS 模块导入导出 ==========

// users.module.ts
@Module({
  providers: [UsersService],  // 提供 Service
  exports: [UsersService],    // 导出 Service
})
export class UsersModule {}

// orders.module.ts
@Module({
  imports: [UsersModule],     // 导入 UsersModule
  providers: [OrdersService],
})
export class OrdersModule {}

// 关键点:
// • imports:导入其他模块
// • exports:导出给其他模块使用
// • 与 ES6 语法非常类似

三、@Module 装饰器详解

3.1 四大核心属性

@Module 装饰器结构

typescript
import { Module } from '@nestjs/common';

@Module({
  imports: [],      // 导入其他模块
  controllers: [],  // 控制器
  providers: [],    // 服务提供者
  exports: [],      // 导出给其他模块使用
})
export class AppModule {}

四大属性详解

属性类型说明类比理解
importsModule[]导入其他模块ES6 的 import
controllersController[]处理请求的控制器路由层
providersProvider[]服务提供者(Service)业务逻辑层
exportsProvider[]导出给其他模块使用ES6 的 export

3.2 providers 深入理解

providers 的本质

code
Providers(提供者)理解:
│
├──  本质
│   ├── 依赖注入中的实例化对象
│   ├── 做脏活累活的角色
│   └── 在模块中实现共享
│
├──  典型代表
│   ├── Service(服务)
│   ├── Repository(仓库)
│   ├── Factory(工厂)
│   └── Helper(辅助工具)
│
├──  注意事项
│   ├── providers 不能导入模块
│   ├── 可能导致循环依赖
│   └── 由框架自动管理实例化
│
└──  简化理解
    └── providers = Service 层的容器

代码示例

typescript
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  // 控制器:处理请求
  controllers: [UsersController],
  
  // 提供者:业务逻辑
  providers: [UsersService],
  
  // 导出:供其他模块使用
  exports: [UsersService],
})
export class UsersModule {}

// 使用示例
// src/orders/orders.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from '../users/users.module';
import { OrdersController } from './orders.controller';
import { OrdersService } from './orders.service';

@Module({
  // 导入 UsersModule,可以使用其导出的 UsersService
  imports: [UsersModule],
  
  controllers: [OrdersController],
  providers: [OrdersService],
})
export class OrdersModule {}

// orders.service.ts
import { Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';

@Injectable()
export class OrdersService {
  //  可以注入 UsersService(因为 UsersModule 导出了它)
  constructor(private readonly usersService: UsersService) {}

  async createOrder(userId: number, orderData: any) {
    // 使用 UsersService
    const user = await this.usersService.findOne(userId);
    // ...
  }
}

3.3 TypeScript 类型提示

IDE 友好性

typescript
// 按 Command/Ctrl 点击 @Module 装饰器

// @nestjs/common/decorators/modules/module.decorator.ts
export declare function Module(metadata: ModuleMetadata): ClassDecorator;

// @nestjs/common/interfaces/modules/module-metadata.interface.ts
export interface ModuleMetadata {
    /**
     * 可选的导入模块列表
     * 这些模块中导出的提供者在此模块中可用
     */
    imports?: Array<Type<any> | DynamicModule | Promise<DynamicModule>>;

    /**
     * 要实例化的控制器列表
     */
    controllers?: Array<Type<any>>;

    /**
     * 要实例化的提供者列表
     * 它们可以注入到此模块的其他组件中
     */
    providers?: Provider[];

    /**
     * 要导出的提供者列表
     * 它们应该在此模块导入的其他模块中可用
     */
    exports?: Array<DynamicModule | Promise<DynamicModule> | string | symbol | Provider | ForwardReference>;
}

//  TypeScript 提供完整的类型提示和注释
//  不确定如何使用时,可以查看接口定义

四、四种模块类型

4.1 功能模块(Feature Module)

概念说明

功能模块是按业务功能划分的模块,如用户模块、订单模块、消息模块等。

特点

code
功能模块特点:
│
├──  按业务功能划分
│   ├── 用户模块(UsersModule)
│   ├── 订单模块(OrdersModule)
│   └── 消息模块(ChatModule)
│
├──  高内聚
│   ├── 相关功能聚合在一起
│   └── 边界清晰
│
└──  可组合
    └── 多个功能模块组成完整应用

代码示例

typescript
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { UsersRepository } from './users.repository';

@Module({
  controllers: [UsersController],
  providers: [UsersService, UsersRepository],
  exports: [UsersService],
})
export class UsersModule {}

// src/orders/orders.module.ts
import { Module } from '@nestjs/common';
import { OrdersController } from './orders.controller';
import { OrdersService } from './orders.service';

@Module({
  controllers: [OrdersController],
  providers: [OrdersService],
  exports: [OrdersService],
})
export class OrdersModule {}

// src/chat/chat.module.ts
import { Module } from '@nestjs/common';
import { ChatController } from './chat.controller';
import { ChatService } from './chat.service';

@Module({
  controllers: [ChatController],
  providers: [ChatService],
  exports: [ChatService],
})
export class ChatModule {}

4.2 共享模块(Shared Module)

概念说明

共享模块用于存放各个模块共用的功能,类似于前端的公共组件库。

特点

code
共享模块特点:
│
├──  跨模块共享
│   ├── 多个模块共用
│   └── 避免代码重复
│
├──  导出公共 Provider
│   └── Service、Helper 等
│
└──  被其他模块导入
    └── import 后即可使用

代码示例

typescript
// src/common/common.module.ts
import { Module } from '@nestjs/common';
import { LoggerService } from './logger.service';
import { ConfigService } from './config.service';
import { UtilsService } from './utils.service';

@Module({
  providers: [LoggerService, ConfigService, UtilsService],
  exports: [LoggerService, ConfigService, UtilsService], // 导出公共 Service
})
export class SharedModule {}

// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { SharedModule } from '../common/common.module';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [SharedModule], // 导入共享模块
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

// users.service.ts
import { Injectable } from '@nestjs/common';
import { LoggerService } from '../common/logger.service';

@Injectable()
export class UsersService {
  //  可以使用 SharedModule 导出的 Service
  constructor(private readonly logger: LoggerService) {}

  findAll() {
    this.logger.log('查询所有用户');
    // ...
  }
}

4.3 全局模块(Global Module)

概念说明

全局模块一旦注册,其导出的 Provider 在所有模块中都可用,无需重复导入。

特点

code
全局模块特点:
│
├──  全局可用
│   ├── 无需在每个模块中导入
│   └── 类似全局变量
│
├──  一次性注册
│   └── 在根模块导入一次即可
│
└──  适用场景
    ├── 数据库连接
    ├── 日志服务
    └── 配置服务

代码示例

typescript
// src/database/database.module.ts
import { Module, Global } from '@nestjs/common';
import { DatabaseService } from './database.service';

@Global() //  声明为全局模块
@Module({
  providers: [DatabaseService],
  exports: [DatabaseService], // 导出后全局可用
})
export class DatabaseModule {}

// src/app.module.ts
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { UsersModule } from './users/users.module';

@Module({
  imports: [
    DatabaseModule, // 只需在根模块导入一次
    UsersModule,
  ],
})
export class AppModule {}

// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../database/database.service';

@Injectable()
export class UsersService {
  //  无需导入 DatabaseModule,直接注入即可
  constructor(private readonly database: DatabaseService) {}

  findAll() {
    return this.database.query('SELECT * FROM users');
  }
}

//  注意:
// 全局模块虽然方便,但会降低代码可读性
// 建议只在真正全局的服务上使用(如数据库、日志、配置)

4.4 动态模块(Dynamic Module)

概念说明

动态模块支持按需初始化,类似于前端的懒加载,在需要使用时才进行初始化。

特点

code
动态模块特点:
│
├── ⏱ 按需初始化
│   ├── 使用时才初始化
│   └── 减少启动时间
│
├──  动态配置
│   ├── 运行时传入配置
│   └── 灵活可配置
│
├──  前端类比
│   ├── 图片懒加载
│   ├── 路由懒加载
│   └── 组件懒加载
│
└──  记忆技巧
    └── 动态模块 = 懒加载模块

代码示例

typescript
// src/database/database.module.ts
import { Module, DynamicModule, Global } from '@nestjs/common';
import { DatabaseService } from './database.service';

export interface DatabaseModuleOptions {
  host: string;
  port: number;
  username: string;
  password: string;
  database: string;
}

@Global()
@Module({})
export class DatabaseModule {
  /**
   * 动态注册方法
   * @param options 数据库配置
   * @returns DynamicModule
   */
  static forRoot(options: DatabaseModuleOptions): DynamicModule {
    return {
      module: DatabaseModule,
      providers: [
        {
          provide: 'DATABASE_OPTIONS',
          useValue: options,
        },
        DatabaseService,
      ],
      exports: [DatabaseService],
    };
  }

  /**
   * 异步注册方法
   * @param options 异步配置
   * @returns DynamicModule
   */
  static forRootAsync(options: {
    useFactory: (...args: any[]) => Promise<DatabaseModuleOptions> | DatabaseModuleOptions;
    inject?: any[];
  }): DynamicModule {
    return {
      module: DatabaseModule,
      providers: [
        {
          provide: 'DATABASE_OPTIONS',
          useFactory: options.useFactory,
          inject: options.inject || [],
        },
        DatabaseService,
      ],
      exports: [DatabaseService],
    };
  }
}

// ========== 使用示例 ==========

// src/app.module.ts
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    // 方式一:同步配置
    DatabaseModule.forRoot({
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'password',
      database: 'test',
    }),

    // 方式二:异步配置(推荐)
    DatabaseModule.forRootAsync({
      useFactory: (configService: ConfigService) => ({
        host: configService.get('DATABASE_HOST'),
        port: configService.get('DATABASE_PORT'),
        username: configService.get('DATABASE_USERNAME'),
        password: configService.get('DATABASE_PASSWORD'),
        database: configService.get('DATABASE_NAME'),
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

//  forRoot 和 forRootAsync 的命名约定:
// • forRoot:静态配置
// • forRootAsync:异步配置
// • 这是 NestJS 社区约定俗成的命名方式

动态模块的实际应用

typescript
// TypeORM 动态模块示例
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'password',
      database: 'test',
      entities: [],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

//  TypeOrmModule.forRoot() 就是动态模块
//  只有在应用启动时才会初始化数据库连接

五、模块组织最佳实践

5.1 目录结构规范

推荐的项目结构

code
project-root/
│
├── src/
│   ├── common/                    # 公共模块
│   │   ├── common.module.ts       # 共享模块
│   │   ├── filters/               # 过滤器
│   │   ├── guards/                # 守卫
│   │   ├── interceptors/          # 拦截器
│   │   ├── pipes/                 # 管道
│   │   ├── decorators/            # 自定义装饰器
│   │   └── interfaces/            # 公共接口
│   │
│   ├── config/                    # 配置模块
│   │   ├── config.module.ts
│   │   └── configuration.ts
│   │
│   ├── database/                  # 数据库模块
│   │   ├── database.module.ts
│   │   └── migrations/
│   │
│   ├── users/                     # 用户模块(功能模块)
│   │   ├── users.module.ts
│   │   ├── users.controller.ts
│   │   ├── users.service.ts
│   │   ├── users.repository.ts
│   │   ├── dto/
│   │   │   ├── create-user.dto.ts
│   │   │   └── update-user.dto.ts
│   │   ├── entities/
│   │   │   └── user.entity.ts
│   │   └── interfaces/
│   │       └── user.interface.ts
│   │
│   ├── orders/                    # 订单模块(功能模块)
│   │   ├── orders.module.ts
│   │   ├── orders.controller.ts
│   │   ├── orders.service.ts
│   │   └── ...
│   │
│   ├── app.module.ts              # 根模块
│   └── main.ts                    # 应用入口
│
├── test/                          # 测试文件
├── nest-cli.json                  # NestJS CLI 配置
├── tsconfig.json                  # TypeScript 配置
└── package.json                   # 项目依赖

5.2 模块划分原则

code
模块划分原则:
│
├──  按业务功能划分
│   ├── 用户模块(UsersModule)
│   ├── 订单模块(OrdersModule)
│   ├── 商品模块(ProductsModule)
│   └── 支付模块(PaymentsModule)
│
├──  高内聚低耦合
│   ├── 相关功能聚合在一个模块
│   ├── 模块之间依赖最小化
│   └── 避免循环依赖
│
├──  单一职责
│   ├── 每个模块只负责一个业务领域
│   ├── 不要创建"上帝模块"
│   └── 合理拆分大型模块
│
└──  共享逻辑提取
    ├── 公共功能放入 SharedModule
    ├── 全局服务放入 GlobalModule
    └── 避免重复代码

5.3 避免循环依赖

循环依赖问题

typescript
//  循环依赖示例

// users.module.ts
@Module({
  imports: [OrdersModule], // UsersModule 依赖 OrdersModule
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

// orders.module.ts
@Module({
  imports: [UsersModule], // OrdersModule 依赖 UsersModule
  providers: [OrdersService],
  exports: [OrdersService],
})
export class OrdersModule {}

//  问题:UsersModule ⇄ OrdersModule 形成循环依赖

解决方案

typescript
//  解决方案一:使用 forwardRef

// users.module.ts
import { Module, forwardRef } from '@nestjs/common';

@Module({
  imports: [forwardRef(() => OrdersModule)],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

// orders.module.ts
import { Module, forwardRef } from '@nestjs/common';

@Module({
  imports: [forwardRef(() => UsersModule)],
  providers: [OrdersService],
  exports: [OrdersService],
})
export class OrdersModule {}

//  解决方案二:提取共享模块

// common.module.ts
@Module({
  providers: [SharedService],
  exports: [SharedService],
})
export class SharedModule {}

// users.module.ts
@Module({
  imports: [SharedModule], // 依赖 SharedModule 而非 OrdersModule
  providers: [UsersService],
})
export class UsersModule {}

// orders.module.ts
@Module({
  imports: [SharedModule], // 依赖 SharedModule 而非 UsersModule
  providers: [OrdersService],
})
export class OrdersModule {}

//  解决方案三:重新设计架构(推荐)
// 检查是否真的需要相互依赖,可能需要重构业务逻辑

六、完整项目示例

6.1 根模块配置

main.ts - 应用入口

typescript
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // 全局验证管道
  app.useGlobalPipes(new ValidationPipe());
  
  // 全局前缀
  app.setGlobalPrefix('api/v1');
  
  // 启用 CORS
  app.enableCors();
  
  await app.listen(3000);
  console.log('Application is running on: http://localhost:3000/api/v1');
}
bootstrap();

app.module.ts - 根模块

typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';

// 导入功能模块
import { UsersModule } from './users/users.module';
import { OrdersModule } from './orders/orders.module';
import { AuthModule } from './auth/auth.module';

// 导入共享模块
import { SharedModule } from './common/common.module';

// 导入数据库模块
import { DatabaseModule } from './database/database.module';

// 导入控制器和服务
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    // ========== 全局配置 ==========
    ConfigModule.forRoot({
      isGlobal: true, // 全局配置
      envFilePath: '.env',
    }),
    
    // ========== 数据库配置(动态模块)==========
    DatabaseModule.forRoot({
      type: 'mysql',
      host: process.env.DATABASE_HOST,
      port: parseInt(process.env.DATABASE_PORT, 10),
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME,
      entities: [],
      synchronize: true,
    }),
    
    // ========== 共享模块 ==========
    SharedModule,
    
    // ========== 功能模块 ==========
    UsersModule,
    OrdersModule,
    AuthModule,
  ],
  
  // 根模块的控制器
  controllers: [AppController],
  
  // 根模块的服务
  providers: [AppService],
})
export class AppModule {}

app.controller.ts - 根控制器

typescript
// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

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

  @Get('health')
  healthCheck() {
    return {
      status: 'ok',
      timestamp: new Date().toISOString(),
    };
  }
}

app.service.ts - 根服务

typescript
// src/app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

6.2 完整功能模块示例

用户模块完整结构

typescript
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { UsersRepository } from './users.repository';
import { User } from './entities/user.entity';
import { SharedModule } from '../common/common.module';

@Module({
  imports: [
    TypeOrmModule.forFeature([User]), // 注册实体
    SharedModule, // 导入共享模块
  ],
  controllers: [UsersController],
  providers: [UsersService, UsersRepository],
  exports: [UsersService], // 导出供其他模块使用
})
export class UsersModule {}

// src/users/users.controller.ts
import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  Put,
  Delete,
  UseGuards,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';

@Controller('users')
@UseGuards(JwtAuthGuard) // 控制器级别的守卫
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id);
  }

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(+id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

// src/users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { LoggerService } from '../common/logger.service';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    private readonly logger: LoggerService, // 从 SharedModule 注入
  ) {}

  async findAll(): Promise<User[]> {
    this.logger.log('查询所有用户');
    return this.userRepository.find();
  }

  async findOne(id: number): Promise<User> {
    const user = await this.userRepository.findOne({ where: { id } });
    if (!user) {
      throw new NotFoundException(`用户 #${id} 不存在`);
    }
    return user;
  }

  async create(createUserDto: CreateUserDto): Promise<User> {
    const user = this.userRepository.create(createUserDto);
    return this.userRepository.save(user);
  }

  async update(id: number, updateUserDto: UpdateUserDto): Promise<User> {
    const user = await this.findOne(id);
    Object.assign(user, updateUserDto);
    return this.userRepository.save(user);
  }

  async remove(id: number): Promise<void> {
    const user = await this.findOne(id);
    await this.userRepository.remove(user);
  }
}

// src/users/entities/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 100 })
  name: string;

  @Column({ unique: true })
  email: string;

  @Column()
  password: string;

  @Column({ default: true })
  isActive: boolean;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;
}

// src/users/dto/create-user.dto.ts
import { IsString, IsEmail, MinLength, MaxLength } from 'class-validator';

export class CreateUserDto {
  @IsString()
  @MinLength(2)
  @MaxLength(100)
  name: string;

  @IsEmail()
  email: string;

  @IsString()
  @MinLength(6)
  password: string;
}

// src/users/dto/update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';

export class UpdateUserDto extends PartialType(CreateUserDto) {}

七、四种模块类型对比

7.1 对比表

模块类型特点应用场景示例
功能模块按业务功能划分业务功能UsersModule、OrdersModule
共享模块跨模块共享公共功能SharedModule、CommonModule
全局模块全局可用,无需导入数据库、日志、配置DatabaseModule、LoggerModule
动态模块按需初始化,灵活配置懒加载、运行时配置DatabaseModule.forRoot()

7.2 选择指南

code
模块类型选择指南:
│
├──  功能模块
│   └── 需要独立业务功能时使用
│
├──  共享模块
│   └── 多个模块需要共用某个 Service 时使用
│
├──  全局模块
│   └── 全局通用服务(数据库、日志、配置)时使用
│
└── ⏱ 动态模块
    └── 需要按需初始化或动态配置时使用

八、常见问题与解决方案

问题原因解决方案
Service 无法注入未在 providers 中注册在 Module 的 providers 中添加 Service
无法使用其他模块的 Service未导入模块或模块未导出 Serviceimport 模块 + exports Service
循环依赖错误A 依赖 B,B 依赖 A使用 forwardRef 或重新设计架构
全局模块不生效未使用 @Global() 装饰器添加 @Global() 装饰器
动态模块配置无效forRoot 参数错误检查配置格式和参数类型
providers 导入模块误解 providers 的作用providers 只能注册 Provider,不能导入 Module
模块重复导入不必要的重复导入检查 imports,移除重复项
Service 实例不共享多个模块分别实例化使用 SharedModule 或 GlobalModule

九、学习要点总结

核心要点

  1. 模块化本质:类似于前端组件化,但颗粒度更大,用于组织应用
  2. 四大属性:imports、controllers、providers、exports
  3. 四种类型:功能模块、共享模块、全局模块、动态模块
  4. providers 理解:Service 层的容器,做脏活累活,实现依赖注入
  5. 最佳实践:按业务功能划分、高内聚低耦合、避免循环依赖

行动建议

code
学习路径:
│
├──  第一阶段:理解概念(1-2 天)
│   ├── 理解模块化和组件化的关系
│   ├── 理解 @Module 四大属性
│   └── 理解四种模块类型
│
├──  第二阶段:实践练习(1 周)
│   ├── 创建功能模块(用户、订单)
│   ├── 创建共享模块(日志、工具)
│   ├── 创建全局模块(数据库)
│   └── 创建动态模块(配置)
│
└──  第三阶段:项目应用(持续)
    ├── 设计合理的模块架构
    ├── 解决循环依赖问题
    └── 优化模块组织结构

十、延伸学习资源

官方资源

练习建议

  1. 练习 1:创建一个完整的功能模块(用户模块)
  2. 练习 2:创建共享模块,实现跨模块共享 Service
  3. 练习 3:创建全局模块,实现全局日志服务
  4. 练习 4:创建动态模块,实现数据库配置
  5. 练习 5:解决一个循环依赖问题

延伸思考

code
思考题:
│
├──  什么时候使用共享模块,什么时候使用全局模块?
├──  如何避免循环依赖?
├──  动态模块和普通模块的本质区别是什么?
├──  如何设计一个合理的模块架构?
└──  providers 为什么不能导入模块?

附录:模块化速查表

概念说明关键词
功能模块按业务功能划分UsersModule、OrdersModule
共享模块跨模块共享功能SharedModule、exports
全局模块全局可用@Global()、无需导入
动态模块按需初始化forRoot()、懒加载
imports导入其他模块导入后可用其 exports
exports导出供其他模块使用被 import 后可用
providers注册服务Service、Repository
controllers注册控制器处理请求

笔记整理完成时间:2026-03-07
下一章节预告:NestJS 数据库集成实战