三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

flat-server架构设计揭秘:模块化Controller与Service的最佳实践

flat-server架构设计揭秘:模块化Controller与Service的最佳实践

flat-server架构设计揭秘:模块化Controller与Service的最佳实践

【免费下载链接】flat-serverA Node.js server for the Agora Flat open source classroom.项目地址: https://gitcode.com/gh_mirrors/fl/flat-server

flat-server作为Agora Flat开源教室的Node.js服务端实现,其架构设计采用了高度模块化的Controller与Service分层模式,为大规模实时交互应用提供了清晰的代码组织和高效的开发体验。本文将深入剖析这一架构的核心设计理念、实现方式及最佳实践,帮助开发者快速掌握模块化开发的精髓。

一、Controller层:请求处理的第一道防线

Controller层作为应用的入口,负责接收和验证客户端请求,并将处理结果返回给客户端。flat-server通过装饰器模式抽象基类实现了Controller的标准化和复用。

1.1 抽象Controller基类设计

所有业务Controller均继承自AbstractController,该基类定义了请求处理的生命周期和通用方法:

export abstract class AbstractController<REQ, RES> { public constructor(params: ControllerClassParams) { // 初始化请求上下文、日志等公共资源 } public abstract execute(): Promise<RES>; }

这种设计确保了所有Controller具有一致的接口和行为,便于框架统一管理请求流程。

1.2 装饰器驱动的路由定义

通过@Controller装饰器,开发者可以 declarative 方式定义路由信息和请求验证规则:

@Controller<RequestType, ResponseType>({ method: "POST", path: "/api/v1/cloud-storage/list", auth: true, }) export class CloudStorageList extends AbstractController<RequestType, ResponseType> { public async execute(): Promise<ResponseType> { // 业务逻辑实现 } }

装饰器不仅简化了路由配置,还实现了关注点分离,使Controller专注于业务逻辑而非框架细节。

1.3 模块化的Controller组织

项目按业务领域划分Controller模块,如用户管理、房间管理、云存储等,每个模块独立维护:

  • 用户相关:src/v1/controller/user/
  • 房间相关:src/v1/controller/room/
  • 云存储相关:src/v1/controller/cloudStorage/

这种组织方式使代码结构清晰,便于团队协作和功能扩展。

二、Service层:业务逻辑的核心实现

Service层负责封装核心业务逻辑,实现与数据访问层的交互,并为Controller提供数据支持。flat-server通过领域驱动设计依赖注入实现了Service的高内聚低耦合。

2.1 领域划分的Service设计

Service按业务领域划分为用户服务、房间服务、云存储服务等,每个Service专注于特定领域的业务逻辑:

// 用户服务 export class ServiceUser { constructor(private userUUID: string) {} public async getNameAndAvatar(): Promise<{name: string, avatar: string}> { // 获取用户信息的业务逻辑 } } // 房间服务 export class ServiceRoom { constructor(private roomUUID: string, private userUUID: string) {} public async create(params: RoomCreateParams): Promise<Room> { // 创建房间的业务逻辑 } }

2.2 依赖注入与服务定位

通过Service Locator模式,flat-server实现了Service的解耦和按需实例化:

// 服务注册 export const initService = (): void => { registerService("oss", (ids?: IDS) => { return new AliOSSService(ids); }); }; // 服务使用 const oss = useOnceService("oss", this.ids);

这种设计使Service之间的依赖关系更加清晰,便于单元测试和模块替换。

2.3 事务管理与数据一致性

Service层通过TypeORM实现数据库事务管理,确保复杂业务操作的数据一致性:

// 在Service中使用事务 public async createRoom(params: RoomParams): Promise<Room> { return this.DBTransaction.manager.transaction(async manager => { // 执行一系列数据库操作 const room = await manager.save(Room, params); await manager.save(RoomUser, {roomUUID: room.uuid, userUUID: this.userUUID}); return room; }); }

三、Controller与Service的协作模式

flat-server中Controller与Service的协作遵循单一职责原则,形成了清晰的调用链和数据流。

3.1 请求处理流程

  1. 请求接收:Controller接收客户端请求
  2. 参数验证:验证请求参数合法性
  3. 服务调用:实例化并调用Service处理业务逻辑
  4. 结果返回:将Service返回的结果格式化后返回
// Controller中的典型实现 export class CreateOrdinary extends AbstractController<RequestType, ResponseType> { private readonly room: ServiceRoom; public constructor(params: ControllerClassParams) { super(params); this.room = new ServiceRoom(this.roomUUID, this.userUUID); } public async execute(): Promise<ResponseType> { // 参数验证 this.validateParams(); // 调用Service处理业务逻辑 const result = await this.room.create(this.body); // 返回处理结果 return { roomUUID: result.uuid, inviteCode: result.inviteCode, }; } }

3.2 错误处理机制

通过自定义错误类ControllerErrorFError,实现了错误的统一处理和状态码映射:

// 错误定义 export class ControllerError extends FlatError { constructor(errorCode: ErrorCode, message?: string) { super(errorCode, message); this.name = "ControllerError"; } } // 错误使用 throw new ControllerError(ErrorCode.RoomNotFound);

这种机制确保了错误信息在Controller和Service层之间的一致传递和处理。

四、最佳实践与设计模式

flat-server的架构设计融合了多种设计模式和最佳实践,为构建可维护、可扩展的服务端应用提供了范例。

4.1 装饰器模式的应用

除了路由定义,装饰器还被广泛用于权限控制、日志记录等横切关注点:

// 登录验证装饰器 export const Login = (): MethodDecorator => { return (target, propertyKey, descriptor) => { // 实现登录验证逻辑 }; };

4.2 仓储模式的数据访问

通过DAO层封装数据访问逻辑,使Service层与具体数据存储技术解耦:

// DAO实现 export class DAO { public async find<T>(model: EntityTarget<T>, conditions: FindConditions<T>): Promise<T | undefined> { return dataSource.getRepository(model).findOne({where: conditions}); } }

4.3 策略模式的服务实现

针对不同的第三方服务(如OSS、合规检查),采用策略模式实现统一接口下的不同实现:

// 抽象策略接口 export abstract class OSSAbstract { abstract getUploadUrl(params: UploadParams): Promise<UploadUrlResult>; } // 具体策略实现 export class AliOSSService extends OSSAbstract { public async getUploadUrl(params: UploadParams): Promise<UploadUrlResult> { // 阿里云OSS实现 } }

五、总结与扩展

flat-server的模块化Controller与Service架构设计,通过清晰的职责划分、灵活的依赖管理和丰富的设计模式应用,为构建高性能、可维护的实时交互服务提供了坚实基础。开发者在实践中可以:

  1. 遵循单一职责:确保每个Controller和Service只负责一个功能领域
  2. 依赖注入优先:通过依赖注入减少组件间耦合,提高可测试性
  3. 异常统一处理:使用自定义错误类实现一致的错误处理机制
  4. 模块化组织:按业务领域划分代码结构,提高代码可读性和可维护性

通过这些实践,开发者可以构建出更加健壮、灵活和易于扩展的服务端应用,为用户提供稳定可靠的实时交互体验。

【免费下载链接】flat-serverA Node.js server for the Agora Flat open source classroom.项目地址: https://gitcode.com/gh_mirrors/fl/flat-server

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

← 返回列表