Files
2026-05-27 18:07:55 +08:00

357 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 分层架构设计
<cite>
**本文档引用的文件**
- [main.go](file://cmd/server/main.go)
- [router.go](file://internal/router/router.go)
- [config.go](file://internal/config/config.go)
- [database.go](file://internal/config/database.go)
- [meilisearch_config.go](file://internal/config/meilisearch.go)
- [redis_config.go](file://internal/config/redis.go)
- [mysql.go](file://internal/database/mysql.go)
- [redis.go](file://internal/cache/redis.go)
- [meilisearch.go](file://internal/search/meilisearch.go)
- [health.go](file://internal/handler/health.go)
- [brand.go](file://internal/handler/brand.go)
- [model.go](file://internal/handler/model.go)
- [brand_repository.go](file://internal/repository/brand.go)
- [brand_model.go](file://internal/model/brand.go)
- [logger_middleware.go](file://internal/middleware/logger.go)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本项目采用分层架构设计,围绕表现层(Router/Handler)、业务层(Repository)、数据访问层(Database/Cache/Search)与基础设施层(Middleware/Logger)进行职责分离。通过构造函数注入依赖的方式,实现清晰的依赖关系与可测试性。MVC 的变体实现体现在:表现层负责路由与请求响应;业务层封装领域逻辑与查询;数据访问层抽象数据库、缓存与搜索引擎;基础设施层提供横切关注点如日志、CORS、请求 ID 等。
## 项目结构
项目按功能域分层组织,核心目录如下:
- cmd/server:应用入口,负责初始化配置、连接外部服务、启动 HTTP 服务器
- internal/config:配置加载与校验,支持环境变量覆盖
- internal/router:路由注册与中间件装配
- internal/handlerHTTP 处理器,面向路由端点,调用仓库与工具
- internal/repository:业务仓储,封装数据库查询与映射
- internal/database:数据库连接与池化配置
- internal/cacheRedis 客户端初始化
- internal/searchMeilisearch 客户端初始化与搜索接口
- internal/middlewareGin 中间件,统一处理日志、CORS、请求 ID
- internal/model:领域模型定义
- internal/response:统一响应封装
- pkg/encode:编码工具(如 Base64
- pkg/logger:日志初始化
```mermaid
graph TB
subgraph "表现层"
Router["Router<br/>internal/router/router.go"]
Handlers["Handlers<br/>internal/handler/*"]
end
subgraph "业务层"
Repositories["Repositories<br/>internal/repository/*"]
Models["Models<br/>internal/model/*"]
end
subgraph "数据访问层"
DB["MySQL 连接<br/>internal/database/mysql.go"]
Redis["Redis 客户端<br/>internal/cache/redis.go"]
Search["Meilisearch 客户端<br/>internal/search/meilisearch.go"]
end
subgraph "基础设施层"
Middleware["中间件<br/>internal/middleware/*"]
LoggerPkg["日志包<br/>pkg/logger/*"]
Encode["编码工具<br/>pkg/encode/*"]
end
subgraph "入口"
Main["主程序<br/>cmd/server/main.go"]
Config["配置<br/>internal/config/*"]
end
Main --> Config
Main --> DB
Main --> Redis
Main --> Search
Main --> Router
Router --> Middleware
Router --> Handlers
Handlers --> Repositories
Repositories --> DB
Handlers --> Redis
Handlers --> Search
Handlers --> Encode
Handlers --> LoggerPkg
```
**图示来源**
- [main.go:1-96](file://cmd/server/main.go#L1-L96)
- [router.go:1-42](file://internal/router/router.go#L1-L42)
- [mysql.go:1-47](file://internal/database/mysql.go#L1-L47)
- [redis.go:1-17](file://internal/cache/redis.go#L1-L17)
- [meilisearch.go:1-46](file://internal/search/meilisearch.go#L1-L46)
- [config.go:1-64](file://internal/config/config.go#L1-L64)
**章节来源**
- [main.go:1-96](file://cmd/server/main.go#L1-L96)
- [router.go:1-42](file://internal/router/router.go#L1-L42)
- [config.go:1-64](file://internal/config/config.go#L1-L64)
## 核心组件
- 表现层(Router/Handler
- 路由器负责注册路由组与中间件,将 HTTP 请求映射到处理器
- 处理器接收请求参数,调用仓库或外部服务,返回统一响应
- 业务层(Repository
- 封装数据库查询逻辑,负责数据读取与映射
- 数据访问层(Database/Cache/Search
- 提供数据库连接池、Redis 客户端与 Meilisearch 客户端
- 基础设施层(Middleware/Logger
- 提供日志、CORS、请求 ID 等横切能力
**章节来源**
- [router.go:14-41](file://internal/router/router.go#L14-L41)
- [brand.go:19-24](file://internal/handler/brand.go#L19-L24)
- [brand_repository.go:16-18](file://internal/repository/brand.go#L16-L18)
- [mysql.go:14-46](file://internal/database/mysql.go#L14-L46)
- [redis.go:10-16](file://internal/cache/redis.go#L10-L16)
- [meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20)
- [logger_middleware.go:10-45](file://internal/middleware/logger.go#L10-L45)
## 架构总览
下图展示了从入口到各层的完整调用链路与依赖方向:
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Main as "主程序<br/>cmd/server/main.go"
participant Router as "路由器<br/>internal/router/router.go"
participant Handler as "处理器<br/>internal/handler/*"
participant Repo as "仓库<br/>internal/repository/*"
participant DB as "数据库<br/>internal/database/mysql.go"
participant Redis as "Redis<br/>internal/cache/redis.go"
participant Search as "Meilisearch<br/>internal/search/meilisearch.go"
Client->>Main : 启动进程
Main->>Main : 加载配置/初始化日志
Main->>DB : 打开数据库连接
Main->>Redis : 创建客户端
Main->>Search : 创建客户端
Main->>Router : 注册路由与中间件
Client->>Router : 发起 HTTP 请求
Router->>Handler : 调用对应处理器
Handler->>Repo : 执行业务查询
Repo->>DB : 执行 SQL 查询
DB-->>Repo : 返回结果集
Repo-->>Handler : 返回领域对象列表
Handler-->>Client : 统一响应
```
**图示来源**
- [main.go:22-64](file://cmd/server/main.go#L22-L64)
- [router.go:14-41](file://internal/router/router.go#L14-L41)
- [brand.go:30-35](file://internal/handler/brand.go#L30-L35)
- [brand_repository.go:31-50](file://internal/repository/brand.go#L31-L50)
- [mysql.go:28-46](file://internal/database/mysql.go#L28-L46)
## 详细组件分析
### 表现层(Router/Handler
- 路由器在入口中被创建,并注入日志、数据库、搜索与 Redis 客户端
- 注册健康检查、品牌、型号、设备等路由组与端点
- 处理器通过构造函数注入数据库连接与日志实例,确保单一职责与可测试性
```mermaid
classDiagram
class Router {
+New(log, db, searchClient, redis) Engine
}
class HealthHandler {
+Check(c)
}
class BrandHandler {
-repo BrandRepository
-log Logger
+GetBrand(c)
}
class ModelHandler {
-repo ModelRepository
-log Logger
+GetModel(c)
}
Router --> HealthHandler : "注册路由"
Router --> BrandHandler : "注册路由"
Router --> ModelHandler : "注册路由"
```
**图示来源**
- [router.go:14-41](file://internal/router/router.go#L14-L41)
- [health.go:8-18](file://internal/handler/health.go#L8-L18)
- [brand.go:14-24](file://internal/handler/brand.go#L14-L24)
- [model.go:14-24](file://internal/handler/model.go#L14-L24)
**章节来源**
- [router.go:14-41](file://internal/router/router.go#L14-L41)
- [health.go:8-18](file://internal/handler/health.go#L8-L18)
- [brand.go:19-24](file://internal/handler/brand.go#L19-L24)
- [model.go:19-24](file://internal/handler/model.go#L19-L24)
### 业务层(Repository
- 仓库封装数据库查询逻辑,使用上下文传递取消信号与超时控制
- 支持条件查询与排序,将结果映射到领域模型
- 通过构造函数注入数据库连接,保持与底层实现解耦
```mermaid
classDiagram
class BrandRepository {
-db sql.DB
+NewBrandRepository(db)
+List(ctx, brandName) []Brand
}
class BrandModel {
+ID int
+Name string
}
BrandRepository --> BrandModel : "返回领域对象"
```
**图示来源**
- [brand_repository.go:12-50](file://internal/repository/brand.go#L12-L50)
- [brand_model.go:3-6](file://internal/model/brand.go#L3-L6)
**章节来源**
- [brand_repository.go:16-18](file://internal/repository/brand.go#L16-L18)
- [brand_repository.go:20-50](file://internal/repository/brand.go#L20-L50)
- [brand_model.go:3-6](file://internal/model/brand.go#L3-L6)
### 数据访问层(Database/Cache/Search
- 数据库连接通过 DSN 配置,设置连接池大小与生命周期,并进行健康检查
- Redis 客户端基于配置创建,用于后续缓存操作
- Meilisearch 客户端封装搜索请求,限制检索字段并解码结果
```mermaid
flowchart TD
Start(["初始化数据访问层"]) --> DBInit["创建数据库连接<br/>internal/database/mysql.go"]
DBInit --> DBPool["设置连接池参数"]
DBPool --> DBPing["执行健康检查"]
DBPing --> RedisInit["创建 Redis 客户端<br/>internal/cache/redis.go"]
DBPing --> SearchInit["创建 Meilisearch 客户端<br/>internal/search/meilisearch.go"]
RedisInit --> End(["完成"])
SearchInit --> End
```
**图示来源**
- [mysql.go:14-46](file://internal/database/mysql.go#L14-L46)
- [redis.go:10-16](file://internal/cache/redis.go#L10-L16)
- [meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20)
**章节来源**
- [mysql.go:14-46](file://internal/database/mysql.go#L14-L46)
- [redis.go:10-16](file://internal/cache/redis.go#L10-L16)
- [meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20)
### 基础设施层(Middleware/Logger
- 日志中间件记录状态码、路径、耗时、IP、请求 ID 等信息,并按级别输出
- 请求 ID 中间件为每个请求生成唯一标识,便于追踪
- CORS 中间件允许跨域访问
```mermaid
flowchart TD
Req["请求进入"] --> ReqID["生成/获取请求ID"]
ReqID --> LogMW["日志中间件记录"]
LogMW --> CORS["CORS 中间件"]
CORS --> Handler["处理器执行"]
Handler --> Resp["响应返回"]
```
**图示来源**
- [logger_middleware.go:10-45](file://internal/middleware/logger.go#L10-L45)
**章节来源**
- [logger_middleware.go:10-45](file://internal/middleware/logger.go#L10-L45)
### 配置管理(Config
- 配置加载支持环境变量覆盖,分别加载数据库、Meilisearch、Redis 的配置
- 在生产环境与开发环境之间切换默认值
- 提供地址格式化方法与环境变量读取辅助函数
```mermaid
flowchart TD
Load["加载配置"] --> Env["解析环境变量"]
Env --> DB["加载数据库配置"]
Env --> MS["加载 Meilisearch 配置"]
Env --> RD["加载 Redis 配置"]
DB --> ValidateDB["校验数据库配置"]
MS --> ValidateMS["校验 Meilisearch 配置"]
RD --> ValidateRD["校验 Redis 配置"]
ValidateDB --> Done["返回配置对象"]
ValidateMS --> Done
ValidateRD --> Done
```
**图示来源**
- [config.go:18-56](file://internal/config/config.go#L18-L56)
- [database.go:17-71](file://internal/config/database.go#L17-L71)
- [meilisearch_config.go:14-50](file://internal/config/meilisearch.go#L14-L50)
- [redis_config.go:16-56](file://internal/config/redis.go#L16-L56)
**章节来源**
- [config.go:18-56](file://internal/config/config.go#L18-L56)
- [database.go:17-71](file://internal/config/database.go#L17-L71)
- [meilisearch_config.go:14-50](file://internal/config/meilisearch.go#L14-L50)
- [redis_config.go:16-56](file://internal/config/redis.go#L16-L56)
## 依赖分析
- 入口依赖配置、数据库、缓存与搜索引擎,然后构建路由器
- 路由器依赖中间件与处理器,处理器依赖仓库与日志
- 仓库依赖数据库连接,处理器可选依赖缓存与搜索引擎
- 配置模块独立于业务层,提供环境化参数
```mermaid
graph LR
Main["cmd/server/main.go"] --> Config["internal/config/*"]
Main --> DB["internal/database/mysql.go"]
Main --> Redis["internal/cache/redis.go"]
Main --> Search["internal/search/meilisearch.go"]
Main --> Router["internal/router/router.go"]
Router --> Middleware["internal/middleware/*"]
Router --> Handlers["internal/handler/*"]
Handlers --> Repositories["internal/repository/*"]
Repositories --> DB
Handlers --> Redis
Handlers --> Search
Handlers --> Logger["pkg/logger/*"]
```
**图示来源**
- [main.go:22-64](file://cmd/server/main.go#L22-L64)
- [router.go:14-41](file://internal/router/router.go#L14-L41)
**章节来源**
- [main.go:22-64](file://cmd/server/main.go#L22-L64)
- [router.go:14-41](file://internal/router/router.go#L14-L41)
## 性能考虑
- 数据库连接池:设置最大打开连接数、空闲连接数与连接生命周期,减少连接开销
- 上下文超时:仓库查询使用上下文传递超时,避免阻塞
- 编码优化:处理器支持 Base64 编码响应,降低传输体积但增加 CPU 开销,需按场景权衡
- 中间件顺序:日志中间件应置于末尾以统计真实耗时
[本节为通用指导,无需特定文件来源]
## 故障排除指南
- 数据库连接失败:检查配置中的主机、端口、用户名与密码;确认网络可达与安全组放行
- Meilisearch 搜索异常:确认索引名称与 API Key 正确,检查网络连通性
- Redis 连接问题:核对主机、端口与认证信息,验证目标数据库编号
- 日志输出异常:确认日志初始化成功与环境变量设置正确
- 响应编码错误:当启用 Base64 编码时,确保编码流程无异常并返回合适的状态码
**章节来源**
- [main.go:38-58](file://cmd/server/main.go#L38-L58)
- [brand.go:32-43](file://internal/handler/brand.go#L32-L43)
- [meilisearch.go:27-29](file://internal/search/meilisearch.go#L27-L29)
## 结论
该分层架构通过清晰的职责划分与依赖注入,实现了表现层、业务层、数据访问层与基础设施层的解耦。MVC 变体在本项目中体现为:路由与处理器承担表现层职责,仓库承载业务逻辑,数据库/缓存/搜索引擎作为数据访问层,中间件与日志作为基础设施。建议在扩展新功能时遵循“高层不依赖低层”的原则,保持构造函数注入与接口隔离,持续优化连接池与查询性能,并完善监控与告警体系。