feat: 开发broker相关代码,开发全局代码

This commit is contained in:
R524809
2025-11-18 18:01:04 +08:00
parent a9d7fc9038
commit 7acadf191f
29 changed files with 3149 additions and 106 deletions

View File

@@ -0,0 +1,714 @@
# NestJS 模块生成指南
## 快速生成完整模块
### 方法一:使用 `resource` 命令(推荐)
一次性生成包含 module、controller、service、entity 的完整 CRUD 资源:
```bash
# 生成 user 模块(会在 src/modules/user 目录下创建所有文件)
pnpm nest g resource modules/user
# 或者使用别名
pnpm nest g res modules/user
```
**交互式选项:**
- `What transport layer do you use?` → 选择 `REST API`
- `Would you like to generate CRUD entry points?` → 选择 `Yes`
**生成的文件结构:**
```
src/modules/user/
├── user.controller.ts # 控制器
├── user.controller.spec.ts # 控制器测试
├── user.service.ts # 服务
├── user.service.spec.ts # 服务测试
├── user.module.ts # 模块
└── entities/
└── user.entity.ts # 实体TypeORM
```
### 方法二:分别生成各个文件
```bash
# 生成模块
pnpm nest g module modules/user
# 生成控制器
pnpm nest g controller modules/user
# 生成服务
pnpm nest g service modules/user
# 生成实体(需要手动创建,或使用 TypeORM CLI
```
### 方法三:使用 TypeORM 生成实体
```bash
# 安装 TypeORM CLI如果还没有
pnpm add -D typeorm
# 生成实体(需要先配置 TypeORM
pnpm typeorm entity:create -n User
```
## 文件组织模式
### 模式一:按功能模块组织(推荐)⭐
```
src/
├── modules/
│ ├── user/
│ │ ├── user.module.ts
│ │ ├── user.controller.ts
│ │ ├── user.service.ts
│ │ ├── user.entity.ts
│ │ ├── user.dto.ts # DTO 文件
│ │ ├── user.controller.spec.ts
│ │ └── user.service.spec.ts
│ ├── order/
│ │ ├── order.module.ts
│ │ ├── order.controller.ts
│ │ ├── order.service.ts
│ │ ├── order.entity.ts
│ │ └── ...
│ └── product/
│ └── ...
├── database/
│ ├── database.module.ts
│ └── database.config.ts
└── app.module.ts
```
**优点:**
- 模块化清晰,每个功能独立
- 易于维护和扩展
- 符合 NestJS 最佳实践
**适用场景:**
- 大型企业级应用
- 需要复杂业务逻辑
- 需要清晰的架构分层
## 推荐的文件组织(当前项目)
基于你的项目结构,推荐使用**模式一**
```
src/
├── modules/ # 业务模块
│ ├── user/
│ │ ├── user.module.ts
│ │ ├── user.controller.ts
│ │ ├── user.service.ts
│ │ ├── user.entity.ts
│ │ ├── dto/ # DTO 文件(可选)
│ │ │ ├── create-user.dto.ts
│ │ │ └── update-user.dto.ts
│ │ └── interfaces/ # 接口定义(可选)
│ │ └── user.interface.ts
│ ├── order/
│ └── product/
├── database/ # 数据库配置
│ ├── database.module.ts
│ └── database.config.ts
├── common/ # 公共模块(可选)
│ ├── filters/
│ ├── guards/
│ ├── interceptors/
│ └── pipes/
└── app.module.ts
```
## 实际生成示例
### 生成 user 模块
```bash
# 1. 生成完整资源
cd /Users/joey-xd/sites/vest-mind/vest-mind-backend/apps/api
pnpm nest g resource modules/user
# 2. 选择选项:
# - REST API
# - Yes (生成 CRUD)
```
### 生成后的文件内容示例
**user.entity.ts:**
```typescript
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}
```
**user.service.ts:**
```typescript
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Injectable()
export class UserService {
create(createUserDto: CreateUserDto) {
return 'This action adds a new user';
}
findAll() {
return `This action returns all user`;
}
findOne(id: number) {
return `This action returns a #${id} user`;
}
update(id: number, updateUserDto: UpdateUserDto) {
return `This action updates a #${id} user`;
}
remove(id: number) {
return `This action removes a #${id} user`;
}
}
```
**user.controller.ts:**
```typescript
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@Get()
findAll() {
return this.userService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.userService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.userService.remove(+id);
}
}
```
## 常用生成命令速查
```bash
# 生成资源(完整 CRUD
pnpm nest g resource modules/user
# 生成模块
pnpm nest g module modules/user
# 生成控制器
pnpm nest g controller modules/user
# 生成服务
pnpm nest g service modules/user
# 生成守卫
pnpm nest g guard modules/user/guards/auth
# 生成拦截器
pnpm nest g interceptor modules/user/interceptors/logging
# 生成过滤器
pnpm nest g filter modules/user/filters/http-exception
# 生成管道
pnpm nest g pipe modules/user/pipes/validation
# 生成装饰器
pnpm nest g decorator modules/user/decorators/roles
```
## 注意事项
1. **路径规范:**
- 使用 `modules/模块名` 作为路径
- 会自动创建目录结构
2. **自动导入:**
- 生成的文件会自动导入到相应的模块中
- 如果不想自动导入,使用 `--skip-import` 选项
3. **测试文件:**
- 默认会生成 `.spec.ts` 测试文件
- 使用 `--no-spec` 可以跳过测试文件生成
4. **扁平结构:**
- 使用 `--flat` 可以生成扁平结构(所有文件在同一目录)
- 不推荐使用,会破坏模块化结构
## DTOData Transfer Object详解
### 什么是 DTO
DTOData Transfer Object是数据传输对象用于在不同层之间传输数据。在 NestJS 中DTO 主要用于:
1. **定义 API 请求和响应的数据结构**
2. **数据验证**(结合 `class-validator`
3. **类型安全**
4. **API 文档生成**(结合 Swagger
### 为什么需要 DTO
#### 1. 数据验证
```typescript
// 没有 DTO - 不安全
@Post()
create(@Body() body: any) {
// body 可能是任何数据,没有验证
return this.userService.create(body);
}
// 使用 DTO - 安全
@Post()
create(@Body() createUserDto: CreateUserDto) {
// 数据已经验证,类型安全
return this.userService.create(createUserDto);
}
```
#### 2. 类型安全
```typescript
// DTO 定义了明确的数据结构
export class CreateUserDto {
username: string;
email: string;
age: number;
}
// TypeScript 会检查类型
const user = new CreateUserDto();
user.username = 'john'; // ✅ 正确
user.age = '25'; // ❌ TypeScript 错误
```
#### 3. API 文档
使用 Swagger 时DTO 会自动生成 API 文档:
```typescript
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ description: '用户名', example: 'john' })
username: string;
@ApiProperty({ description: '邮箱', example: 'john@example.com' })
email: string;
}
```
### DTO 的类型
#### 1. Create DTO创建数据
用于创建新资源时的数据验证:
```typescript
// dto/create-user.dto.ts
import {
IsString,
IsEmail,
IsOptional,
MinLength,
MaxLength,
} from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ description: '用户名', example: 'john' })
@IsString()
@MinLength(3)
@MaxLength(20)
username: string;
@ApiProperty({ description: '邮箱', example: 'john@example.com' })
@IsEmail()
email: string;
@ApiProperty({ description: '密码', example: 'password123' })
@IsString()
@MinLength(6)
password: string;
@ApiProperty({ description: '年龄', example: 25, required: false })
@IsOptional()
@IsNumber()
age?: number;
}
```
#### 2. Update DTO更新数据
用于更新资源时的数据验证:
```typescript
// dto/update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
// 方式一:使用 PartialType推荐
export class UpdateUserDto extends PartialType(CreateUserDto) {}
// 方式二:手动定义(更灵活)
// export class UpdateUserDto {
// @IsOptional()
// @IsString()
// username?: string;
//
// @IsOptional()
// @IsEmail()
// email?: string;
// }
```
#### 3. Query DTO查询参数
用于查询列表时的参数验证:
```typescript
// dto/query-user.dto.ts
import { IsOptional, IsNumber, Min, Max } from 'class-validator';
import { Type } from 'class-transformer';
export class QueryUserDto {
@IsOptional()
@Type(() => Number)
@IsNumber()
@Min(1)
page?: number = 1;
@IsOptional()
@Type(() => Number)
@IsNumber()
@Min(1)
@Max(100)
limit?: number = 10;
@IsOptional()
@IsString()
search?: string;
@IsOptional()
@IsString()
sortBy?: string = 'createdAt';
@IsOptional()
@IsString()
sortOrder?: 'ASC' | 'DESC' = 'DESC';
}
```
#### 4. Response DTO响应数据
用于定义 API 响应的数据结构:
```typescript
// dto/user-response.dto.ts
import { ApiProperty } from '@nestjs/swagger';
export class UserResponseDto {
@ApiProperty({ description: '用户ID', example: 1 })
id: number;
@ApiProperty({ description: '用户名', example: 'john' })
username: string;
@ApiProperty({ description: '邮箱', example: 'john@example.com' })
email: string;
@ApiProperty({ description: '创建时间', example: '2024-01-01T00:00:00Z' })
createdAt: Date;
@ApiProperty({ description: '更新时间', example: '2024-01-01T00:00:00Z' })
updatedAt: Date;
}
```
### 在 Controller 中使用 DTO
```typescript
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Query,
} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { QueryUserDto } from './dto/query-user.dto';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@Get()
findAll(@Query() queryUserDto: QueryUserDto) {
return this.userService.findAll(queryUserDto);
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.userService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
}
```
### 启用全局验证管道
`main.ts` 中启用全局验证:
```typescript
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 启用全局验证管道
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // 自动删除不在 DTO 中的属性
forbidNonWhitelisted: true, // 如果请求包含未定义的属性,抛出错误
transform: true, // 自动转换类型(如字符串转数字)
transformOptions: {
enableImplicitConversion: true,
},
}),
);
await app.listen(3000);
}
```
### 常用验证装饰器
```typescript
import {
IsString, // 字符串
IsNumber, // 数字
IsBoolean, // 布尔值
IsEmail, // 邮箱
IsUrl, // URL
IsDate, // 日期
IsOptional, // 可选字段
IsNotEmpty, // 非空
MinLength, // 最小长度
MaxLength, // 最大长度
Min, // 最小值
Max, // 最大值
IsEnum, // 枚举
IsArray, // 数组
IsObject, // 对象
ValidateNested, // 嵌套对象验证
IsUUID, // UUID
Matches, // 正则匹配
} from 'class-validator';
```
### DTO 示例:完整的用户模块
```typescript
// dto/create-user.dto.ts
import {
IsString,
IsEmail,
IsOptional,
MinLength,
IsNumber,
Min,
Max,
} from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ description: '用户名', example: 'john' })
@IsString()
@MinLength(3)
@MaxLength(20)
username: string;
@ApiProperty({ description: '邮箱', example: 'john@example.com' })
@IsEmail()
email: string;
@ApiProperty({ description: '密码', example: 'password123' })
@IsString()
@MinLength(6)
password: string;
@ApiProperty({ description: '年龄', example: 25, required: false })
@IsOptional()
@IsNumber()
@Min(18)
@Max(100)
age?: number;
}
```
```typescript
// dto/update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {}
```
```typescript
// dto/query-user.dto.ts
import { IsOptional, IsNumber, IsString, Min, Max } from 'class-validator';
import { Type } from 'class-transformer';
export class QueryUserDto {
@IsOptional()
@Type(() => Number)
@IsNumber()
@Min(1)
page?: number = 1;
@IsOptional()
@Type(() => Number)
@IsNumber()
@Min(1)
@Max(100)
limit?: number = 10;
@IsOptional()
@IsString()
search?: string;
}
```
### 安装必要的依赖
```bash
# 安装验证库
pnpm add class-validator class-transformer
# 如果使用 Swagger可选
pnpm add @nestjs/swagger swagger-ui-express
```
### DTO vs Entity
| 特性 | DTO | Entity |
| -------- | ---------------------- | ------------------- |
| **用途** | 数据传输和验证 | 数据库模型 |
| **位置** | `dto/` 目录 | `entities/` 目录 |
| **验证** | 使用 `class-validator` | 使用 TypeORM 装饰器 |
| **暴露** | 暴露给 API 客户端 | 不直接暴露 |
| **示例** | `CreateUserDto` | `User` entity |
**最佳实践:**
- ✅ Entity 包含数据库字段(如 `id`, `createdAt`
- ✅ DTO 只包含客户端需要传递的字段
- ✅ 使用 DTO 转换 Entity避免暴露敏感信息
### DTO 转换示例
```typescript
// service 中使用
@Injectable()
export class UserService {
async create(createUserDto: CreateUserDto): Promise<User> {
// DTO → Entity
const user = this.userRepository.create({
username: createUserDto.username,
email: createUserDto.email,
// 不直接传递 password需要加密
passwordHash: await this.hashPassword(createUserDto.password),
});
return this.userRepository.save(user);
}
async findAll(queryDto: QueryUserDto): Promise<User[]> {
// 使用 DTO 中的查询参数
return this.userRepository.find({
skip: (queryDto.page - 1) * queryDto.limit,
take: queryDto.limit,
});
}
}
```
## 最佳实践
1.**使用 `resource` 命令生成完整模块**
2.**按功能模块组织文件**
3.**每个模块包含module、controller、service、entity**
4.**DTO 文件放在模块目录下的 `dto/` 子目录**
5.**为每个操作创建对应的 DTOCreate、Update、Query、Response**
6.**使用 `class-validator` 进行数据验证**
7.**使用 `PartialType` 创建 Update DTO**
8.**启用全局验证管道**
9.**区分 DTO 和 Entity不要混用**
10.**公共组件放在 `common/` 目录**
11.**避免使用扁平结构**
12.**避免按类型组织文件**
13.**避免在 Entity 中直接暴露给 API**