模块与控制器基础:@Module 装饰器详解、控制器创建、路由与 HTTP 方法映射
在 NestJS 中,模块(Module)是组织代码的基本单元,而控制器(Controller)负责处理传入的 HTTP 请求并返回响应。本章将深入解析 @Module() 装饰器的核心配置,演示如何创建控制器,并建立路由与 HTTP 方法之间的映射关系。
1. @Module 装饰器详解
@Module() 装饰器将一个类标记为 NestJS 模块,它是应用架构的“骨架”。每个模块通过元数据对象声明其内部的组件、对外暴露的服务以及依赖的其他模块。
| 属性 | 类型 | 说明 |
|---|---|---|
controllers |
Array<Type<any>> |
该模块下需要实例化的控制器集合,负责处理路由 |
providers |
Array<Type<any>> |
该模块中可被注入的服务、仓库、工厂等提供者 |
imports |
Array<Type<any>> |
导入其他模块,以使用其导出的提供者 |
exports |
Array<Type<any>> |
将本模块的部分提供者暴露给导入本模块的其他模块 |
关键原则:模块是单例作用域。默认情况下,提供者在模块内是单例的,且模块本身也是单例的——无论被导入多少次,Nest 只会创建一个实例。
// app.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users/users.controller';
import { UsersService } from './users/users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class AppModule {}
2. 控制器(Controller)创建
控制器使用 @Controller() 装饰器定义,其核心职责是:
- 接收特定路径的 HTTP 请求
- 调用业务逻辑(通常委托给服务层)
- 返回响应给客户端
@Controller() 可以接收一个可选参数——路由前缀。前缀有助于对相关端点进行分组,避免路由冲突。
// users.controller.ts
import { Controller, Get } from '@nestjs/common';
@Controller('users') // 路由前缀:/users
export class UsersController {
@Get()
findAll(): string {
return '返回所有用户';
}
}
最佳实践:始终为控制器设置有意义的路由前缀(如
users、orders),这不仅能提升代码可读性,还能在全局前缀或版本控制时保持灵活性。
3. 路由与 HTTP 方法映射
NestJS 为每个标准 HTTP 方法提供了对应的装饰器:@Get()、@Post()、@Put()、@Delete()、@Patch() 等。这些装饰器可以接收一个路径参数,用于定义子路由。
| 装饰器 | HTTP 方法 | 典型用途 |
|---|---|---|
@Get() |
GET | 查询资源列表或单个资源 |
@Post() |
POST | 创建新资源 |
@Put() |
PUT | 全量更新资源 |
@Delete() |
DELETE | 删除资源 |
@Patch() |
PATCH | 部分更新资源 |
// users.controller.ts
import { Controller, Get, Post, Param, Body } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return '获取所有用户';
}
@Get(':id')
findOne(@Param('id') id: string): string {
return `获取用户 ${id}`;
}
@Post()
create(@Body() createUserDto: any): string {
return `创建用户:${JSON.stringify(createUserDto)}`;
}
}
路由冲突注意:当存在静态路由(如
@Get('profile'))和动态路由(如 @Get(':id'))时,静态路由必须声明在动态路由之前,否则 Nest 会将 profile 匹配为 :id 参数。
4. 模块与控制器协作流程
下图展示了 NestJS 启动时,模块如何加载控制器,以及请求如何通过路由映射到达控制器方法:
5. 完整示例:用户模块
以下是一个包含模块、控制器和基本路由映射的完整示例:
// 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 {}
// users.controller.ts
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
@Controller('users')
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: any) {
return this.usersService.create(createUserDto);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: any) {
return this.usersService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
}
路由映射总结:
GET /users→findAll()GET /users/:id→findOne()POST /users→create()PUT /users/:id→update()DELETE /users/:id→remove()