1.NestJs简介
什么是 NestJS?
NestJS 是一个基于 TypeScript 和 Node.js 的后端框架,用于构建可维护且高效的服务器端应用程序。它采用了现代的、面向对象的编程风格,并借鉴了 Angular 框架的设计原则,使得它在开发 Web 应用时能够提供一种模块化、可测试和易于理解的方式。NestJS 提供了强大的工具和抽象层,帮助开发人员快速构建可扩展的、可维护的应用程序。
为什么选择 NestJS?
- TypeScript 支持:NestJS 采用 TypeScript 作为主要编程语言,这意味着你可以利用静态类型检查、强大的代码智能感知和更好的代码质量控制。TypeScript 还提供了面向对象编程的优点,使得代码更易于维护和重构。
- 模块化架构:NestJS 使用模块化的设计,将应用程序分割成多个可重用的模块。这种结构有助于保持代码的组织结构清晰,便于团队协作,并且支持快速开发和测试。
- 依赖注入:NestJS 使用依赖注入容器,使得管理依赖关系和组件变得更加容易。这有助于解耦组件,并使代码更容易测试和重用。
- 内置支持:NestJS 提供了内置的模块和库,用于处理常见的任务,例如 HTTP 请求处理、WebSockets、WebSocket Gateways、身份验证、授权等。这些功能可以大大加速开发过程。
- 可扩展性:NestJS 提供了丰富的生态系统,包括中间件、插件、拦截器和自定义装饰器,允许你根据需要扩展框架的功能。
- 社区和文档:NestJS 拥有活跃的社区和详细的文档,这意味着你可以轻松找到支持和解决问题。
NestJS 的优势(详细介绍与代码案例)
1. 模块化架构
NestJS 的模块化架构使得应用程序的组织和拓展变得非常容易。每个模块都可以包含控制器、服务和其他组件。以下是一个简单的例子:
typescriptCopy code// 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 {}
这个模块定义了一个控制器和一个服务,并将它们关联在一起。其他模块可以导入并使用 CatsModule 提供的功能。
2. 依赖注入
NestJS 使用依赖注入容器来管理组件之间的依赖关系。这意味着你可以轻松地将依赖项传递给你的组件,而不必手动创建它们。以下是一个示例:
// cats.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class CatsService {
private readonly cats: string[] = [];
create(cat: string) {
this.cats.push(cat);
}
findAll() {
return this.cats;
}
}
在这个示例中,@Injectable() 装饰器将 CatsService 标记为可注入的服务。你可以在其他组件中通过构造函数来注入这个服务。
3. HTTP 请求处理
NestJS 提供了强大的 HTTP 请求处理功能。以下是一个简单的控制器示例:
e// cats.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CatsService } from './cats.service';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Post()
async create(@Body() catData: { name: string }) {
this.catsService.create(catData.name);
}
@Get()
async findAll() {
return this.catsService.findAll();
}
}
这个控制器处理 POST 和 GET 请求,并使用 @Body() 装饰器来解析请求体中的数据。
NestJS 的优势还包括错误处理、身份验证、WebSocket 支持等等。它提供了一个完整的工具集,使得构建复杂的后端应用程序变得更加容易。希望这些示例能帮助你理解 NestJS 的潜力和优势。
2.初始化NestJs项目
当你开始学习 NestJS 时,首先需要安装 Node.js 和 NestJS CLI,然后创建一个新的 NestJS 项目,并了解项目结构。下面是详细的解释和实际的商业案例。
1. 安装 Node.js 和 NestJS CLI
Node.js 安装:
Node.js 是 NestJS 的运行环境,你需要先安装 Node.js。你可以在 Node.js 官方网站(nodejs.org/)上下载并安装最新版本。
NestJS CLI 安装:
NestJS CLI 是一个命令行工具,用于创建、管理和构建 NestJS 项目。你可以使用以下命令全局安装 NestJS CLI:
npm install -g @nestjs/cli
2. 创建一个新的 NestJS 项目
要创建一个新的 NestJS 项目,你可以运行以下命令:
nest new project-name
这将创建一个名为 project-name 的新 NestJS 项目。在此过程中,你可以选择使用 TypeScript 或 JavaScript,以及其他配置选项。
3. 项目结构解析
NestJS 项目的结构通常如下所示:
project-name/
├── dist/ # 编译生成的代码目录
├── node_modules/ # 依赖模块目录
├── src/ # 源代码目录
│ ├── main.ts # 应用程序的入口文件
│ ├── app.module.ts # 主模块文件
│ ├── ... # 其他模块、控制器、服务等的文件
├── test/ # 测试文件目录
├── tsconfig.json # TypeScript 配置文件
├── package.json # 项目依赖和脚本配置
├── nest-cli.json # NestJS CLI 配置文件
项目结构解析:
-
dist/:这个目录包含了 TypeScript 代码编译生成的 JavaScript 代码。它是运行应用程序的目录。 -
node_modules/:这个目录包含了项目所依赖的 Node.js 模块。它通常由 npm 或 yarn 自动管理。 -
src/:这是主要的源代码目录,包含了应用程序的核心逻辑。main.ts:这是应用程序的入口文件,通常包含了创建 NestJS 应用程序实例的代码。app.module.ts:这是主模块文件,它定义了应用程序的根模块。在这里,你可以配置各种模块、控制器、服务等。
-
test/:这个目录包含了测试文件,用于编写单元测试和端到端测试。 -
tsconfig.json:这是 TypeScript 的配置文件,定义了 TypeScript 项目的编译选项。 -
package.json:这个文件包含了项目的依赖项列表、脚本配置和其他元数据。 -
nest-cli.json:这是 NestJS CLI 的配置文件,它包含了一些项目特定的配置,如项目名称、数据库配置等。
商业案例示例:
假设你正在开发一个电子商务应用程序。你可以使用 NestJS 创建一个后端服务,处理用户的购物车和订单。项目结构如上所示。
在 src/ 目录下,你可以创建一个 carts 模块,其中包括控制器、服务和模型,用于管理用户的购物车。而 orders 模块可以用于处理用户的订单,包括订单的创建、支付等操作。
以下是一个简化的代码示例:
// src/carts/carts.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CartsService } from './carts.service';
@Controller('carts')
export class CartsController {
constructor(private readonly cartsService: CartsService) {}
@Post()
async addToCart(@Body() productData: { productId: number, quantity: number }) {
// 添加商品到购物车
return this.cartsService.addToCart(productData);
}
@Get()
async getCart() {
// 获取购物车内容
return this.cartsService.getCart();
}
}
在这个例子中,CartsController 处理了添加商品到购物车和获取购物车内容的 HTTP 请求。
typescriptCopy code// src/carts/carts.service.ts
import { Injectable } from '@nestjs/common';
import { Product } from './product.model';
@Injectable()
export class CartsService {
private cart: Product[] = [];
addToCart(productData: { productId: number, quantity: number }) {
// 根据 productId 和数量将商品添加到购物车
// 更新购物车内容
}
getCart() {
// 获取购物车内容
return this.cart;
}
}
CartsService 负责管理购物车的状态和操作。
这只是一个简单的示例,但它演示了如何使用 NestJS 创建一个实际的后端服务,以处理电子商务应用程序的购物车功能。项目结构清晰,每个模块都负责特定的功能,使得应用程序易于维护和扩展。
4.自动生成模块代码
NestJS 提供了一个命令来自动生成模块、控制器、服务等代码,这可以大大加速项目的开发。要自动生成模块代码,你可以使用 NestJS CLI 中的 generate 命令。下面是一些示例命令和用法:
自动生成模块代码
要生成一个新的模块,你可以运行以下命令:
nest generate module module-name
这将在项目的 src 目录下创建一个名为 module-name 的新模块。模块将包含一个模块类和一个模块单元测试文件。
自动生成控制器代码
要生成一个新的控制器,你可以运行以下命令:
nest generate controller controller-name
这将在项目的 src 目录下创建一个名为 controller-name 的新控制器。控制器将包含一个控制器类和一个控制器单元测试文件。
自动生成服务代码
要生成一个新的服务,你可以运行以下命令:
nest generate service service-name
这将在项目的 src 目录下创建一个名为 service-name 的新服务。服务将包含一个服务类和一个服务单元测试文件。
自动生成模块、控制器和服务代码
你还可以一次性生成一个模块、控制器和服务,这对于快速创建新功能模块非常有用。例如,要生成一个名为 products 的模块,其中包含一个控制器和一个服务,可以运行以下命令:
nest generate module products
nest generate controller products
nest generate service products
这将生成与 products 相关的模块、控制器和服务代码。
这些命令将自动生成基本的代码文件,并放置在适当的目录中。你可以根据需要对生成的代码进行自定义和扩展。
注意:在运行生成命令之前,确保你已经在项目根目录下,因为 NestJS CLI 会在当前目录下创建相应的文件和文件夹。
希望这些命令可以帮助你更快地生成 NestJS 项目中的代码模块。
5. CURD自动生成
NestJS CLI 的 nest generate resource 命令可以用来生成具有 RESTful 风格的 CRUD 功能的资源,包括模块、控制器、服务和模型。这个命令能够大大简化创建基本 CRUD 功能的过程。以下是如何使用 nest generate resource 命令创建一个用户管理的 CRUD 资源的示例:
nest generate resource users
上述命令将创建一个名为 "users" 的资源,它会自动生成以下文件和代码:
-
模块文件 (
users.module.ts):这个文件定义了一个 NestJS 模块,其中包括了控制器、服务以及与用户资源相关的路由。模块还将模型(模型类)导入其中,并配置了 TypeORM 实体。
// 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 { User } from './user.entity'; @Module({ imports: [TypeOrmModule.forFeature([User])], controllers: [UsersController], providers: [UsersService], }) export class UsersModule {} -
控制器文件 (
users.controller.ts):这个文件定义了一个控制器类,其中包含了处理与用户资源相关的 HTTP 请求的方法,如 GET、POST、PUT、DELETE。
// src/users/users.controller.ts import { Controller } from '@nestjs/common'; import { Crud, CrudController } from '@nestjsx/crud'; import { User } from './user.entity'; import { UsersService } from './users.service'; @Crud({ model: { type: User }, params: { id: { field: 'id', type: 'number', primary: true, }, }, }) @Controller('users') export class UsersController implements CrudController<User> { constructor(public service: UsersService) {} }控制器使用
@Crud装饰器来自动处理 CRUD 操作。 -
服务文件 (
users.service.ts):这个文件定义了一个服务类,其中包含了与用户资源相关的业务逻辑,如数据库操作。
// src/users/users.service.ts import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { TypeOrmCrudService } from '@nestjsx/crud-typeorm'; import { User } from './user.entity'; @Injectable() export class UsersService extends TypeOrmCrudService<User> { constructor(@InjectRepository(User) repo) { super(repo); } }服务类扩展了
TypeOrmCrudService,这使得它能够处理基本的 CRUD 操作。 -
模型文件 (
user.entity.ts):这个文件定义了用户资源的模型(模型类),它描述了用户数据的结构。
// src/users/user.entity.ts import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() username: string; @Column() email: string; }这个模型类使用 TypeORM 装饰器来定义实体的结构。
现在,你可以在 UsersController 中找到默认的 CRUD 路由,这些路由支持 GET(获取所有用户、获取特定用户)、POST(创建用户)、PUT(更新用户)、DELETE(删除用户)等操作。
例如:
- GET
/users: 获取所有用户 - GET
/users/:id: 获取特定用户 - POST
/users: 创建新用户 - PUT
/users/:id: 更新特定用户 - DELETE
/users/:id: 删除特定用户
使用 nest generate resource 命令可以快速生成一个完整的资源,让你更容易地进行 CRUD 操作的开发。请注意,要使用这个命令,你需要在项目中安装 @nestjsx/crud 包,它提供了用于生成 CRUD 资源的功能。
3.NestJs集成Swagger
NestJS 可以轻松地集成 Swagger 来生成交互式 API 文档。Swagger 是一个流行的工具,用于自动生成、可视化和测试 RESTful API。通过集成 Swagger,你可以为你的 NestJS 项目创建详细的 API 文档,使开发人员和团队能够更轻松地理解和使用你的 API。下面是详细的解释和实际的商业案例。
1. 安装 Swagger 包
首先,你需要安装 @nestjs/swagger 包,它是 NestJS 用于集成 Swagger 的官方库。可以使用以下命令安装:
npm install --save @nestjs/swagger swagger-ui-express
2. 配置 Swagger
在你的 NestJS 项目中,你需要进行一些配置来启用 Swagger。通常,你需要在应用程序的根模块 (app.module.ts) 中进行配置。以下是配置步骤:
a. 导入必要的模块和装饰器
在 app.module.ts 文件中导入以下模块和装饰器:
import { Module } from '@nestjs/common';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
b. 创建 Swagger 文档
在 AppModule 类中,创建一个 Swagger 文档对象,该对象包含了 API 文档的一些基本信息,例如标题、描述、版本等。这个文档对象使用 DocumentBuilder 创建。
const options = new DocumentBuilder()
.setTitle('My API')
.setDescription('My API description')
.setVersion('1.0')
.addTag('users', 'Operations about users')
.build();
在这个示例中,我们设置了 API 的标题、描述、版本,并添加了一个名为 "users" 的标签。
c. 创建 Swagger 模块
接下来,在 AppModule 类中创建一个 Swagger 模块,该模块使用 SwaggerModule 来生成 Swagger 文档并将其与应用程序关联起来。
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document);
这段代码将 Swagger 文档与路径 /api 关联起来,你可以通过访问 /api 来访问 API 文档。
3. 添加 Swagger 注解
现在,你需要在你的控制器类和路由处理方法中添加 Swagger 注解,以描述 API 的操作和参数。以下是一些示例注解:
a. 控制器级别的 Swagger 注解
在控制器类上添加 @ApiTags 注解来定义标签,它用于组织 API 文档中的路由。例如:
import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('users') // 这里的标签应该与创建 Swagger 文档时的标签一致
@Controller('users')
export class UsersController {
// ...
}
b. 方法级别的 Swagger 注解
在路由处理方法上添加 @ApiOperation 注解来描述操作,以及 @ApiResponse 注解来定义响应。例如:
import { Get } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
@ApiTags('users')
@Controller('users')
export class UsersController {
@Get()
@ApiOperation({ summary: 'Get all users' })
@ApiResponse({ status: 200, description: 'List of all users' })
async findAll() {
// ...
}
}
商业案例示例
假设你正在开发一个电子商务平台的后端,你可以使用 Swagger 来生成 API 文档,以便前端开发人员了解和使用你的 API。以下是一个基于用户管理的商业案例示例:
import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { UsersService } from './users.service';
import { CreateUserDto, UpdateUserDto, UserDto } from './user.dto';
@ApiTags('users')
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
@ApiOperation({ summary: 'Get all users' })
@ApiResponse({ status: 200, description: 'List of all users', type: [UserDto] })
async findAll() {
const users = await this.usersService.findAll();
return users.map((user) => new UserDto(user));
}
@Get(':id')
@ApiOperation({ summary: 'Get user by ID' })
@ApiResponse({ status: 200, description: 'User details', type: UserDto })
@ApiResponse({ status: 404, description: 'User not found' })
async findById(@Param('id') id: number) {
const user = await this.usersService.findById(id);
if (!user) {
throw new NotFoundException('User not found');
}
return new UserDto(user);
}
@Post()
@ApiOperation({ summary: 'Create a new user' })
@ApiResponse({ status: 201, description: 'User created successfully', type: UserDto })
async create(@Body() createUserDto: CreateUserDto) {
const user = await this.usersService.create(createUserDto);
return new UserDto(user);
}
@Put(':id')
@ApiOperation({ summary: 'Update user by ID' })
@ApiResponse({ status: 200, description: 'User updated successfully', type: UserDto })
@ApiResponse({ status: 404, description: 'User not found' })
async update(@Param('id') id: number, @Body() updateUserDto: UpdateUserDto) {
const user = await this.usersService.update(id, updateUserDto);
if (!user) {
throw new NotFoundException('User not found');
}
return new UserDto(user);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete user by ID' })
@ApiResponse({ status: 204, description: 'User deleted successfully' })
@ApiResponse({ status: 404, description: 'User not found' })
async delete(@Param('id') id: number) {
const user = await this.usersService.findById(id);
if (!user) {
throw new NotFoundException('User not found');
}
await this.usersService.delete(id);
}
}
在这个示例中,我们定义了一个 UsersController,其中包含了用于获取、创建、更新和删除用户的路由处理方法。Swagger 注解用于描述每个操作和参数,并生成 API 文档。此外,我们还使用了数据传输对象 (DTO) 来定义输入和输出的数据结构。
希望这个示例有助于理解如何在 NestJS 中集成 Swagger 并创建详细的 API 文档。通过 Swagger,你可以为你的商业应用程序提供清晰的文档,帮助开发团队更好地了解和使用你的 API。
4. NestJs装饰器
NestJS 中的装饰器是一种特殊的 TypeScript 语法,用于附加元数据和功能到类、方法、属性等 TypeScript 元素上。装饰器在 NestJS 中被广泛用于控制器、服务、模块和路由等方面,用于实现依赖注入、路由映射、中间件等功能。在下面的解释中,我将详细解释一些常用的 NestJS 装饰器,并提供一个实际的商业案例,以便更好地理解它们的用法。
常用的 NestJS 装饰器
1. @Module
@Module 装饰器用于定义一个 NestJS 模块。模块是应用程序的基本构建块,它包含了控制器、服务和其他相关组件,用于组织代码。
import { Module } from '@nestjs/common';
@Module({
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
在上面的示例中,我们定义了一个名为 UserModule 的 NestJS 模块,该模块包括了 UserController 控制器和 UserService 服务。
2. @Controller
@Controller 装饰器用于定义一个控制器类,它处理客户端请求并返回响应。控制器负责将路由映射到路由处理方法。
import { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UserController {
@Get()
findAll(): string {
return 'Get all users';
}
}
在上面的示例中,我们定义了一个名为 UserController 的控制器类,它处理路由 /users 的 GET 请求。
3. @Injectable
@Injectable 装饰器用于定义一个可注入的服务类。服务类包含应用程序的业务逻辑,可以通过依赖注入的方式在控制器和其他组件中使用。
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {
findAll(): string {
return 'All users data';
}
}
在上面的示例中,我们定义了一个名为 UserService 的可注入的服务类,它包含了 findAll 方法,该方法返回所有用户的数据。
4. @Get, @Post, @Put, @Delete
这些装饰器用于定义路由处理方法,分别处理 GET、POST、PUT 和 DELETE 请求。这些装饰器可以附加到类中的方法上,并指定路由路径。
import { Controller, Get, Post, Put, Delete } from '@nestjs/common';
@Controller('users')
export class UserController {
@Get()
findAll(): string {
return 'Get all users';
}
@Post()
create(): string {
return 'Create a user';
}
@Put(':id')
update(): string {
return 'Update a user';
}
@Delete(':id')
delete(): string {
return 'Delete a user';
}
}
在上面的示例中,我们定义了不同 HTTP 方法的路由处理方法,并附加到相应的装饰器上。
5. @Param, @Body, @Query
这些装饰器用于从请求中提取参数、请求体和查询参数。它们可以附加到路由处理方法的参数上。
import { Controller, Get, Post, Param, Body, Query } from '@nestjs/common';
@Controller('users')
export class UserController {
@Get(':id')
findById(@Param('id') id: string): string {
return `Find user by ID: ${id}`;
}
@Post()
create(@Body() createUserDto: CreateUserDto): string {
return `Create user: ${createUserDto.name}`;
}
@Get()
findAll(@Query('page') page: number, @Query('limit') limit: number): string {
return `Get users with page: ${page}, limit: ${limit}`;
}
}
在上面的示例中,我们使用 @Param 提取路由参数、使用 @Body 提取请求体、使用 @Query 提取查询参数。
商业案例示例
假设你正在开发一个社交媒体应用程序的后端,以下是一个基于用户的商业案例示例,其中使用了上述装饰器:
import { Controller, Get, Post, Param, Body, Query } from '@nestjs/common';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get(':id')
getUserById(@Param('id') id: string): Promise<User> {
return this.userService.getUserById(id);
}
@Post()
createUser(@Body() createUserDto: CreateUserDto): Promise<User> {
return this.userService.createUser(createUserDto);
}
@Get()
getUsers(@Query('page') page: number, @Query('limit') limit: number): Promise<User[]> {
return this.userService.getUsers(page, limit);
}
}
在这个示例中,我们使用了 @Param 提取用户的 ID,@Body 提取用户创建请求中的数据,以及 @Query 提取分页参数。控制器中的路由处理方法调用了一个名为 UserService 的服务,该服务包含了业务逻辑。
希望这个示例和解释有助于你理解 NestJS 中的装饰器的用法,并如何将它们应用于实际的商业案例中。装饰器是 NestJS 强大的功能之一,它可以帮助你更容易地构建和组织复杂的应用程序。
如何自定义装饰器
当你需要为 NestJS 应用程序编写自定义装饰器时,通常是为了增强应用程序的功能或添加特定的元数据。下面我将为你提供一个常见的商业案例,演示如何编写一个自定义装饰器,该装饰器用于记录 HTTP 请求的响应时间。这个案例将包括详细的代码和注释。
商业案例:记录 HTTP 请求响应时间
在一个实际的 NestJS 项目中,你可能希望记录每个路由处理方法的响应时间,以便监测性能和故障排除。我们将创建一个自定义装饰器来实现这个功能。
步骤 1: 创建装饰器
首先,创建一个名为 ResponseTime 的自定义装饰器,它将记录请求的开始时间,并在路由处理方法执行后计算响应时间。我们将使用 performance.now() 函数来测量时间。
import { SetMetadata, UseInterceptors, CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
export function ResponseTime(): MethodDecorator {
return (target: any, key: string | symbol, descriptor: PropertyDescriptor) => {
SetMetadata('responseTime', key)(target, key, descriptor);
UseInterceptors(ResponseTimeInterceptor)(target, key, descriptor);
};
}
class ResponseTimeInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const startTime = performance.now();
return next.handle().pipe(
tap(() => {
const req = context.switchToHttp().getRequest();
const res = context.switchToHttp().getResponse();
const endTime = performance.now();
const responseTime = endTime - startTime;
console.log(`Response time for ${req.method} ${req.url}: ${responseTime}ms`);
}),
);
}
}
在上面的代码中,我们定义了一个名为 ResponseTime 的自定义装饰器。这个装饰器使用 SetMetadata 函数来为路由处理方法附加元数据 'responseTime',以便后续的访问。然后,我们使用 UseInterceptors 函数来为路由处理方法附加 ResponseTimeInterceptor 拦截器,该拦截器将记录响应时间。
步骤 2: 使用自定义装饰器
现在,你可以在你的控制器中使用自定义装饰器来记录响应时间。
import { Controller, Get } from '@nestjs/common';
import { ResponseTime } from './response-time.decorator';
@Controller('users')
export class UsersController {
@Get()
@ResponseTime()
findAll(): string {
// 这里的代码将会记录响应时间
return 'Get all users';
}
}
在上面的示例中,我们在 findAll 方法上应用了 ResponseTime 装饰器,这样每次调用 findAll 方法时都会记录响应时间。
步骤 3: 注册拦截器
最后,不要忘记在你的模块中注册拦截器。
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { UsersController } from './users.controller';
@Module({
controllers: [UsersController],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: ResponseTimeInterceptor,
},
],
})
export class UsersModule {}
在上面的代码中,我们将 ResponseTimeInterceptor 拦截器注册为全局拦截器,这样它将应用于整个应用程序。
日志记录装饰器
步骤 1: 创建自定义装饰器
首先,创建一个名为 Logger 的自定义装饰器,它会记录方法的执行时间和参数,并将这些信息输出到控制台。
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const now = Date.now();
const request = context.switchToHttp().getRequest();
const method = request.method;
const url = request.url;
return next.handle().pipe(
tap(() => {
const elapsedTime = Date.now() - now;
Logger.log(
`${method} ${url} ${elapsedTime}ms`,
context.getClass().name,
);
}),
);
}
}
在上面的示例中,我们创建了一个名为 LoggingInterceptor 的 NestJS 拦截器。拦截器实现了 NestInterceptor 接口,其中的 intercept 方法会在每个请求处理之前和之后执行。
步骤 2: 使用自定义装饰器
接下来,我们将自定义装饰器应用于控制器方法,以记录方法的执行时间和参数。
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { LoggingInterceptor } from './logging.interceptor';
@Controller('users')
export class UsersController {
@Get()
@UseInterceptors(LoggingInterceptor)
findAll(): string {
return 'Get all users';
}
}
在上面的示例中,我们使用 @UseInterceptors 装饰器将 LoggingInterceptor 应用于 findAll 方法。这意味着在每次调用 findAll 方法时,拦截器会记录请求的执行时间和参数。
商业案例示例
假设你正在开发一个电子商务平台的后端,你可以使用自定义装饰器来记录用户的操作,以便监控和分析应用程序的性能。以下是一个简单的示例:
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { LoggingInterceptor } from './logging.interceptor';
@Controller('products')
export class ProductsController {
@Get()
@UseInterceptors(LoggingInterceptor)
findAll(): string {
// 此处执行获取产品列表的逻辑
return 'Get all products';
}
}
在上面的示例中,我们将 LoggingInterceptor 应用于 ProductsController 中的 findAll 方法。每次用户调用 GET /products 时,拦截器会记录请求的执行时间和参数,并将这些信息输出到控制台,从而帮助开发团队监控和优化应用程序的性能。
希望这个自定义装饰器示例有助于你理解如何创建自己的装饰器,并如何将其应用于实际的商业案例中。自定义装饰器是 NestJS 的强大功能之一,可以根据你的需求扩展应用程序的功能。
5. Nestjs Providers
在 NestJS 中,Providers 是应用程序中的基本构建块之一,它们负责处理各种任务,包括处理业务逻辑、数据访问、依赖注入等。本文将详细解释 NestJS Providers,并提供一个实际的商业案例以及详细的注释。
什么是 NestJS Providers?
NestJS Providers 是一个装饰器,用于标识类,使其可以被 NestJS 框架自动管理和依赖注入。它们可以是服务、控制器、拦截器、中间件、管道等各种组件。
在 NestJS 中,Providers 通常包括以下部分:
- 类定义:Provider 类是一个普通的 TypeScript 类,它包含了处理特定任务的方法和属性。
- 装饰器:
@Injectable()装饰器用于标识 Provider 类,以便 NestJS 可以进行依赖注入。这个装饰器是必需的,它告诉 NestJS 这是一个可注入的类。 - 构造函数:Provider 类的构造函数通常包含其他 Provider 的依赖项。这些依赖项由 NestJS 自动注入。
详解 NestJS Providers
让我们通过一个示例来详细了解 NestJS Providers。假设你正在开发一个电子商务平台的后端,以下是一个名为 ProductService 的 Provider,它处理产品相关的业务逻辑和数据访问。
import { Injectable } from '@nestjs/common';
@Injectable()
export class ProductService {
private products: Product[] = [];
// 构造函数中注入依赖的服务或模块
constructor(private readonly logger: Logger) {}
// 创建产品
createProduct(product: CreateProductDto): Product {
const newProduct = { id: uuidv4(), ...product };
this.products.push(newProduct);
this.logger.log(`Product created: ${newProduct.name}`);
return newProduct;
}
// 获取所有产品
getAllProducts(): Product[] {
return this.products;
}
}
在上面的示例中,ProductService 是一个 NestJS Provider。让我们逐步解释:
@Injectable()装饰器标识了ProductService类,使它成为一个可注入的 Provider。- 构造函数中的参数
private readonly logger: Logger是一个依赖项,它是一个内置的 Logger 服务,由 NestJS 自动注入。你可以在 Provider 中使用这个服务来记录日志。 createProduct方法用于创建新的产品,并将其添加到products数组中。在这个过程中,我们记录了产品的创建日志。getAllProducts方法用于获取所有产品的列表。
商业案例示例
现在,让我们看一个实际的商业案例,如何在 NestJS 应用程序中使用 Providers。
假设你的电子商务应用程序有一个 OrderService,它处理订单的创建和管理。OrderService 需要与数据库交互以保存订单信息。以下是一个示例代码:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Order } from './order.entity';
@Injectable()
export class OrderService {
constructor(
@InjectRepository(Order)
private readonly orderRepository: Repository<Order>,
) {}
async createOrder(orderData: CreateOrderDto): Promise<Order> {
const order = new Order();
order.customerName = orderData.customerName;
order.totalAmount = orderData.totalAmount;
return await this.orderRepository.save(order);
}
async getAllOrders(): Promise<Order[]> {
return await this.orderRepository.find();
}
}
在上面的示例中,OrderService 是一个 NestJS Provider,它依赖于 TypeORM 仓库 orderRepository 来执行数据库操作。@InjectRepository(Order) 装饰器用于注入仓库实例,使其在 OrderService 内可用。
这个 Provider 包含了创建订单和获取订单列表的方法,它们通过调用 orderRepository 上的 TypeORM 方法来与数据库交互。
希望这个示例详细解释了 NestJS Providers 的概念和用法,以及如何在实际的商业案例中使用它们。Providers 是 NestJS 中的核心组件之一,用于管理应用程序的业务逻辑和数据访问。
6. NestJs Mongoose详解
NestJS Mongoose 是一种用于与 MongoDB 数据库进行交互的强大工具,它结合了 NestJS 和 Mongoose 库的功能。在本文中,我将详细解释 NestJS Mongoose 的用法,并提供一个实际的商业案例以及详细的注释。
什么是 NestJS Mongoose?
NestJS Mongoose 是 NestJS 框架的一个模块,它简化了在 NestJS 应用程序中使用 MongoDB 数据库的过程。它基于 Mongoose,一个流行的 MongoDB ODM(对象文档映射器),并提供了一种简单而强大的方式来定义模型、进行数据查询、执行数据库操作等。
使用 NestJS Mongoose 时,你可以轻松地将 MongoDB 数据库与 NestJS 的依赖注入系统集成,从而使你的应用程序更容易维护和测试。
安装 NestJS Mongoose
要使用 NestJS Mongoose,首先需要安装必要的依赖:
bashCopy code
npm install --save @nestjs/mongoose mongoose
然后,确保在 NestJS 应用程序中导入 MongooseModule,并配置连接信息。
typescriptCopy codeimport { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/nestjs-mongoose-example'),
],
})
export class AppModule {}
使用 NestJS Mongoose
让我们通过一个商业案例来详细了解如何在 NestJS 应用程序中使用 NestJS Mongoose。假设你正在开发一个博客应用程序,需要将博客文章存储在 MongoDB 数据库中。
步骤 1: 创建 Mongoose 模型
首先,创建一个 Mongoose 模型来定义博客文章的数据结构。在 blog.model.ts 文件中:
import { Schema, Document } from 'mongoose';
export interface Blog extends Document {
title: string;
content: string;
}
export const BlogSchema = new Schema({
title: { type: String, required: true },
content: { type: String, required: true },
});
上面的代码定义了一个 Blog 接口和一个 BlogSchema 模型。Blog 接口描述了博客文章的结构,BlogSchema 定义了数据模型。
步骤 2: 创建 NestJS Service
接下来,创建一个 NestJS Service 来执行博客文章的数据库操作。在 blog.service.ts 文件中:
import { Injectable } from '@nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { Blog } from './blog.model';
@Injectable()
export class BlogService {
constructor(@InjectModel('Blog') private readonly blogModel: Model<Blog>) {}
async createBlog(title: string, content: string): Promise<Blog> {
const newBlog = new this.blogModel({ title, content });
return await newBlog.save();
}
async findAllBlogs(): Promise<Blog[]> {
return await this.blogModel.find().exec();
}
}
上述代码中,我们创建了一个 BlogService,它依赖于 Blog 模型并使用 @InjectModel 注入。
createBlog方法用于创建博客文章并将其保存到数据库中。findAllBlogs方法用于获取所有博客文章。
步骤 3: 创建 NestJS Controller
现在,创建一个 NestJS Controller 来处理 HTTP 请求并调用 BlogService 中的方法。在 blog.controller.ts 文件中:
import { Controller, Post, Get, Body } from '@nestjs/common';
import { BlogService } from './blog.service';
@Controller('blogs')
export class BlogController {
constructor(private readonly blogService: BlogService) {}
@Post()
async createBlog(@Body('title') title: string, @Body('content') content: string) {
const newBlog = await this.blogService.createBlog(title, content);
return newBlog;
}
@Get()
async findAllBlogs() {
const blogs = await this.blogService.findAllBlogs();
return blogs;
}
}
上述代码中,我们创建了一个 BlogController,它包含两个路由处理方法:
createBlog方法处理 POST 请求,用于创建新的博客文章。findAllBlogs方法处理 GET 请求,用于获取所有博客文章。
步骤 4: 创建 NestJS Module
最后,创建一个 NestJS 模块来组织和导入所有的 Provider、Service 和 Controller。在 blog.module.ts 文件中:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { BlogSchema } from './blog.model';
import { BlogService } from './blog.service';
import { BlogController } from './blog.controller';
@Module({
imports: [
MongooseModule.forFeature([{ name: 'Blog', schema: BlogSchema }]),
],
controllers: [BlogController],
providers: [BlogService],
})
export class BlogModule {}
上述代码中,我们导入了 MongooseModule 并使用 MongooseModule.forFeature 注册了 Blog 模型。然后,我们将 BlogController 和 BlogService 添加到模块的 controllers 和 providers 中。
商业案例示例
在上述示例中,我们创建了一个基于 NestJS Mongoose 的博客应用程序。通过定义模型、创建服务、编写控制器和配置模块,我们可以轻松地与 MongoDB 数据库进行交互并构建功能丰富的应用程序。
希望这个示例和解释有助于你理解如何使用 NestJS Mongoose 在实际的商业应用程序中处理数据持久化。这个示例只是一个入门,NestJS Mongoose 提供了更多高级功能,如查询构建器、中间件等,以满足不同的需求。
7. 构建商业项目架构
步骤 1: 创建 NestJS 应用
首先,创建一个 NestJS 应用程序:
bashCopy code
nest new online-store
步骤 2: 集成 MongoDB
使用 @nestjs/mongoose 模块来集成 MongoDB。首先,安装依赖:
bashCopy code
npm install --save @nestjs/mongoose mongoose
然后,在 app.module.ts 中配置 MongoDB 连接:
typescriptCopy codeimport { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/online-store'),
],
controllers: [],
providers: [],
})
export class AppModule {}
步骤 3: 集成 Redis
使用 ioredis 模块来集成 Redis 缓存。首先,安装依赖:
npm install --save ioredis
然后,在 NestJS 中配置 Redis 缓存,在 app.module.ts 中添加以下代码:
import { Module, CacheModule } from '@nestjs/common';
import * as Redis from 'ioredis';
@Module({
imports: [
CacheModule.register({
store: Redis,
host: 'localhost',
port: 6379,
}),
],
controllers: [],
providers: [],
})
export class AppModule {}
步骤 4: 集成 RocketMQ
使用 RocketMQ 作为异步消息队列。RocketMQ 的 Node.js 客户端可用于 NestJS 应用。首先,安装依赖:
npm install --save rocketmq-client-nodejs
然后,在 app.module.ts 中添加以下代码:
import { Module } from '@nestjs/common';
import { RocketMQModule } from '@rocketmq/nest';
@Module({
imports: [
RocketMQModule.forRootAsync({
useFactory: () => ({
namesrvAddr: 'localhost:9876',
}),
}),
],
controllers: [],
providers: [],
})
export class AppModule {}
步骤 5: 用户注册模块
创建用户注册模块,包括控制器、服务和数据库模型。以下是一个示例:
// user.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post('/register')
async register(@Body() createUserDto: CreateUserDto) {
return this.userService.register(createUserDto);
}
}
typescriptCopy code// user.service.ts
import { Injectable } from '@nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
@Injectable()
export class UserService {
constructor(@InjectModel('User') private readonly userModel: Model<User>) {}
async register(createUserDto: CreateUserDto): Promise<User> {
const newUser = new this.userModel(createUserDto);
return await newUser.save();
}
}
typescriptCopy code// user.model.ts
import * as mongoose from 'mongoose';
export const UserSchema = new mongoose.Schema({
// 用户模型定义
});
export interface User extends mongoose.Document {
// 用户模型接口定义
}
步骤 6: 商品模块
创建商品管理模块,包括控制器、服务和数据库模型。以下是一个示例:
typescriptCopy code// product.controller.ts
// 商品控制器代码
// product.service.ts
// 商品服务代码
// product.model.ts
// 商品模型代码
步骤 7: 支付模块
创建支付模块,与微信支付进行接口对接。请查阅微信支付文档以了解如何与微信支付集成。
步骤 8: 订单模块
创建订单模块,包括订单状态流转的逻辑。以下是一个示例:
typescriptCopy code// order.controller.ts
// 订单控制器代码
// order.service.ts
// 订单服务代码
// order.model.ts
// 订单模型代码
步骤 9: 配置路由
在 app.module.ts 中配置路由,将各个模块的路由连接起来。
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { CacheModule } from '@nestjs/common';
import * as Redis from 'ioredis';
import { RocketMQModule } from '@rocketmq/nest';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/online-store'),
CacheModule.register({
store: Redis,
host: 'localhost',
port: 6379,
}),
RocketMQModule.forRootAsync({
useFactory: () => ({
namesrvAddr: 'localhost:9876',
}),
}),
UserModule,
ProductModule,
PaymentModule,
OrderModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
步骤 10: 运行应用
现在,你可以运行应用并测试各个模块的功能:
npm run start
这个示例是一个高级示例,涉及多个模块和技术集成。具体的代码实现和注释可能会根据你的业务需求而有所不同,但这个示例可以作为一个起点,帮助你开始构建一个完整的在线商城系统。确保参考 NestJS、Mongoose、Redis 和 RocketMQ 的官方文档以获取更详细的信息。