nestjs 架构篇:控制器、服务、数据访问

核心架构分层
控制器层

职责​​:处理 HTTP 请求/响应,参数校验,路由分发

设计原则​​:

  • 仅关注 HTTP 协议交互

  • 无业务逻辑,仅调用服务层

  • 使用装饰器定义路由和参数映射

​代码示例​​:

TypeScript 复制代码
// user.controller.ts
@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

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

  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.userService.findOne(id);
  }
}

​关键点​​:

  • @Body()自动解析请求体

  • @Param()提取路由参数

  • 依赖注入 UserService

服务层

职责​​:实现核心业务逻辑,协调数据访问

设计原则​​:

  • 保持无状态(Stateless)

  • 依赖注入数据访问层

  • 使用 DTO 进行数据转换

代码示例​​:

TypeScript 复制代码
// user.service.ts
@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>
  ) {}

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

  async findOne(id: number): Promise<User> {
    return this.userRepository.findOneBy({ id });
  }
}

关键点​​:

  • 使用 TypeORM Repository 进行数据库操作

  • 业务逻辑与数据持久化解耦

数据访问层

职责​​:数据库交互,数据持久化

实现方式​​:

  • ​Repository 模式​​:通过 TypeORM/Prisma 实现

  • ​DAO 模式​​:直接使用数据库驱动

​代码示例​​(TypeORM):

TypeScript 复制代码
// user.entity.ts
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

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

  @CreateDateColumn()
  createdAt: Date;
}

// database.module.ts
@Module({
  imports: [TypeOrmModule.forRoot({
    type: 'postgres',
    host: 'localhost',
    port: 5432,
    entities: [User],
    synchronize: true
  })]
})
export class DatabaseModule {}

关键点​​:

  • 实体类定义数据库表结构

  • 模块化配置数据库连接

模块化架构设计
模块定义规范
TypeScript 复制代码
// user.module.ts
@Module({
  imports: [DatabaseModule],
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService] // 暴露给其他模块
})
export class UserModule {}

核心要素​​:

  • imports:依赖的其他模块

  • exports:导出可复用的组件

  • 默认单例作用域

模块间通信
TypeScript 复制代码
// auth.module.ts
@Module({
  imports: [forwardRef(() => UserModule)] // 解决循环依赖
})
export class AuthModule {}

最佳实践​​:

  • 按业务领域划分模块(如用户、订单、支付)

  • 通过 exports控制服务暴露范围

  • 使用 forwardRef()处理循环依赖

依赖注入系统
依赖注入机制
TypeScript 复制代码
// 服务注入示例
@Controller('orders')
export class OrderController {
  constructor(
    private readonly orderService: OrderService,
    @Inject('PAYMENT_SERVICE') private paymentService: PaymentService
  ) {}
}

实现原理​​:

  • @Injectable()标记可注入类

  • 容器自动解析构造函数参数类型

  • 支持类/值/工厂三种提供者类型

高级注入场景
异步配置注入​​:
TypeScript 复制代码
@Module({
  providers: [{
    provide: 'CONFIG_OPTIONS',
    useFactory: async () => loadConfig()
  }]
})
export class ConfigModule {}
循环依赖解决方案​​:
TypeScript 复制代码
@Module({
  imports: [forwardRef(() => BModule)]
})
export class AModule {}

关键点​​:

  • 优先使用构造函数注入

  • 避免属性注入的隐式依赖

异常处理与数据校验
全局异常过滤器
TypeScript 复制代码
// exceptions.filter.ts
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    response
      .status(500)
      .json({ error: 'Internal Server Error' });
  }
}

// main.ts 注册全局过滤器
app.useGlobalFilters(new AllExceptionsFilter());
数据校验管道
TypeScript 复制代码
// user.dto.ts
export class CreateUserDto {
  @IsEmail()
  email: string;

  @MinLength(6)
  password: string;
}

// 控制器中使用
@Post()
async create(@Body() createUserDto: CreateUserDto) {
  // 自动触发校验
}

关键点​​:

  • 结合 class-validator 实现运行时校验

  • 支持自定义校验器

最佳实践总结
分层架构​
  • 严格区分 Controller/Service/Repository 层

  • 服务层保持无状态,数据访问层封装数据库操作

​模块化设计​
  • 按业务领域划分模块

  • 通过 exports控制服务暴露范围

  • 使用动态模块实现配置化

依赖注入​
  • 优先使用构造函数注入

  • 合理使用作用域(Singleton/Request)

数据持久化​
  • 使用 TypeORM/Prisma 实现 Repository 模式

  • 实体类与数据库表结构严格映射

异常处理​
  • 全局异常过滤器统一处理错误

  • 自定义异常类增强错误语义

相关推荐
消失的旧时光-19435 小时前
Flutter 响应式 + Clean Architecture / MVU 模式 实战指南
android·flutter·架构
Java烘焙师5 小时前
架构师必备:限流方案选型(使用篇)
redis·架构·限流
朱嘉鼎5 小时前
寄存器编写LED程序
stm32·单片机·架构·keilmdk
Layer12 小时前
CommonMark 解析策略与 cmark 工程核心代码解析
架构·markdown·设计
我命由我1234514 小时前
Spring Cloud - Spring Cloud 声明式接口调用(Fiegn 声明式接口调用概述、Fiegn 使用)
java·后端·spring·spring cloud·微服务·架构·java-ee
canonical_entropy14 小时前
领域驱动设计(DDD)中聚合根的最主要职责真的是维护一致性吗?
后端·架构·领域驱动设计
行百里er16 小时前
ES8.6.2 集群部署:教你避坑,笑着搞定高可用
后端·elasticsearch·架构
weixin_4569042716 小时前
Transformer架构发展历史
深度学习·架构·transformer