466 lines
19 KiB
Markdown
466 lines
19 KiB
Markdown
# 数据模型
|
||
|
||
<cite>
|
||
**本文引用的文件**
|
||
- [internal/model/brand.go](file://internal/model/brand.go)
|
||
- [internal/model/model.go](file://internal/model/model.go)
|
||
- [internal/repository/brand.go](file://internal/repository/brand.go)
|
||
- [internal/repository/model.go](file://internal/repository/model.go)
|
||
- [internal/handler/brand.go](file://internal/handler/brand.go)
|
||
- [internal/handler/model.go](file://internal/handler/model.go)
|
||
- [internal/handler/model_list.go](file://internal/handler/model_list.go)
|
||
- [internal/router/router.go](file://internal/router/router.go)
|
||
- [internal/config/database.go](file://internal/config/database.go)
|
||
- [internal/response/response.go](file://internal/response/response.go)
|
||
- [pkg/encode/base64.go](file://pkg/encode/base64.go)
|
||
- [sql/model.sql](file://sql/model.sql)
|
||
- [cmd/server/main.go](file://cmd/server/main.go)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖分析](#依赖分析)
|
||
7. [性能考虑](#性能考虑)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本文件面向 Luxsin 应用 API 的数据模型,系统性梳理 Brand 与 Model 两类数据模型的设计理念、字段定义、约束条件、业务含义以及与数据库表结构的映射关系。文档还覆盖 ORM 映射配置(基于原生 sql.DB 的扫描映射)、模型验证与序列化机制、模型在各层之间的传递方式与性能考量,并给出扩展、版本管理与向后兼容的最佳实践建议。内容兼顾初学者与高级开发者,既提供高层概览,也包含代码级的可视化图示与来源标注。
|
||
|
||
## 项目结构
|
||
该项目采用分层架构:路由层负责请求入口与中间件;处理器层处理业务逻辑与参数解析;仓库层封装数据库访问;模型层承载数据结构;响应层统一返回格式;编码层提供可选的响应体压缩编码;配置层加载数据库等外部服务配置。
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "应用入口"
|
||
MAIN["cmd/server/main.go"]
|
||
end
|
||
subgraph "路由层"
|
||
ROUTER["internal/router/router.go"]
|
||
end
|
||
subgraph "处理器层"
|
||
BRAND_H["internal/handler/brand.go"]
|
||
MODEL_H["internal/handler/model.go"]
|
||
MODEL_LIST_H["internal/handler/model_list.go"]
|
||
end
|
||
subgraph "仓库层"
|
||
BRAND_R["internal/repository/brand.go"]
|
||
MODEL_R["internal/repository/model.go"]
|
||
end
|
||
subgraph "模型层"
|
||
MODEL_M["internal/model/brand.go"]
|
||
MODEL_M2["internal/model/model.go"]
|
||
end
|
||
subgraph "响应与编码"
|
||
RESP["internal/response/response.go"]
|
||
ENCODE["pkg/encode/base64.go"]
|
||
end
|
||
subgraph "配置与数据库"
|
||
DB_CFG["internal/config/database.go"]
|
||
DB_SQL["sql/model.sql"]
|
||
end
|
||
MAIN --> ROUTER
|
||
ROUTER --> BRAND_H
|
||
ROUTER --> MODEL_H
|
||
ROUTER --> MODEL_LIST_H
|
||
BRAND_H --> BRAND_R
|
||
MODEL_H --> MODEL_R
|
||
MODEL_LIST_H --> MODEL_R
|
||
BRAND_R --> MODEL_M
|
||
MODEL_R --> MODEL_M2
|
||
BRAND_H --> RESP
|
||
MODEL_H --> RESP
|
||
MODEL_LIST_H --> RESP
|
||
BRAND_H --> ENCODE
|
||
MODEL_H --> ENCODE
|
||
MODEL_LIST_H --> ENCODE
|
||
DB_CFG --> DB_SQL
|
||
```
|
||
|
||
图表来源
|
||
- [cmd/server/main.go:1-96](file://cmd/server/main.go#L1-L96)
|
||
- [internal/router/router.go:14-42](file://internal/router/router.go#L14-L42)
|
||
- [internal/handler/brand.go:19-50](file://internal/handler/brand.go#L19-L50)
|
||
- [internal/handler/model.go:19-51](file://internal/handler/model.go#L19-L51)
|
||
- [internal/handler/model_list.go:19-57](file://internal/handler/model_list.go#L19-L57)
|
||
- [internal/repository/brand.go:16-51](file://internal/repository/brand.go#L16-L51)
|
||
- [internal/repository/model.go:16-95](file://internal/repository/model.go#L16-L95)
|
||
- [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7)
|
||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||
- [internal/config/database.go:17-72](file://internal/config/database.go#L17-L72)
|
||
- [sql/model.sql:20-38](file://sql/model.sql#L20-L38)
|
||
|
||
章节来源
|
||
- [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64)
|
||
- [internal/router/router.go:14-42](file://internal/router/router.go#L14-L42)
|
||
|
||
## 核心组件
|
||
- 模型层(Model)
|
||
- Brand:承载品牌标识与名称,用于品牌列表查询。
|
||
- Model:承载型号信息,包含品牌名、型号名、形态、设备类型、来源、等价键、创建时间等。
|
||
- 仓库层(Repository)
|
||
- BrandRepository:提供按品牌名模糊查询的品牌列表。
|
||
- ModelRepository:提供按品牌名或型号名模糊查询的型号列表,并处理可空字段的扫描。
|
||
- 处理器层(Handler)
|
||
- BrandHandler:接收查询参数,调用仓库层,支持可选的响应体 Base64 编码。
|
||
- ModelHandler:接收品牌与型号查询参数,调用仓库层,支持可选的响应体 Base64 编码。
|
||
- ModelListHandler:通过搜索客户端返回模型列表,支持可选的响应体 Base64 编码。
|
||
- 响应与编码
|
||
- 统一响应体结构,便于前端解析与错误处理。
|
||
- 可选的自定义 Base64 编码,提升传输效率与隐私保护。
|
||
|
||
章节来源
|
||
- [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7)
|
||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||
- [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51)
|
||
- [internal/repository/model.go:20-95](file://internal/repository/model.go#L20-L95)
|
||
- [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50)
|
||
- [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||
- [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||
|
||
## 架构总览
|
||
下图展示了从请求到响应的关键路径,包括处理器、仓库、数据库与可选编码流程。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as "客户端"
|
||
participant R as "路由层"
|
||
participant H as "处理器层"
|
||
participant Repo as "仓库层"
|
||
participant DB as "数据库"
|
||
participant Enc as "编码层"
|
||
C->>R : "GET /audio/getBrand?brandName=..."
|
||
R->>H : "BrandHandler.GetBrand"
|
||
H->>Repo : "List(brandName)"
|
||
Repo->>DB : "SELECT id,name FROM brand WHERE name LIKE ? ORDER BY name ASC"
|
||
DB-->>Repo : "结果集"
|
||
Repo-->>H : "[]Brand"
|
||
alt "base64Resp=true"
|
||
H->>Enc : "EncodeJSON([]Brand)"
|
||
Enc-->>H : "Base64 字符串"
|
||
H-->>C : "200 OK + Base64"
|
||
else "默认"
|
||
H-->>C : "200 OK + JSON"
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [internal/router/router.go:32-38](file://internal/router/router.go#L32-L38)
|
||
- [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50)
|
||
- [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51)
|
||
- [pkg/encode/base64.go:35-52](file://pkg/encode/base64.go#L35-L52)
|
||
|
||
## 详细组件分析
|
||
|
||
### Brand 数据模型
|
||
- 设计理念
|
||
- 轻量级品牌实体,仅包含标识与名称,用于品牌筛选与列表展示。
|
||
- 字段定义与约束
|
||
- id:整数,主键,自增。
|
||
- name:字符串,非空,用于品牌名匹配与排序。
|
||
- 业务含义
|
||
- 作为 Model 的上游维度,配合 Model 的 brandName 字段形成关联。
|
||
- 数据库映射
|
||
- 表名:brand(未在本文直接列出,但与 Model 的 brand_name 关联一致)。
|
||
- 字段:id、name。
|
||
- ORM 映射配置
|
||
- 使用原生 sql.DB 扫描,通过结构体标签与 Scan 对齐。
|
||
- 验证与序列化
|
||
- 无显式校验逻辑,依赖数据库约束与上层参数清洗。
|
||
- JSON 标签用于序列化输出。
|
||
- 查询流程
|
||
- 支持按品牌名模糊查询,使用 LIKE 匹配并按名称升序排列。
|
||
- 返回 []Brand 列表。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class Brand {
|
||
+int id
|
||
+string name
|
||
}
|
||
class BrandRepository {
|
||
-db *sql.DB
|
||
+List(ctx, brandName) []Brand
|
||
}
|
||
BrandRepository --> Brand : "返回"
|
||
```
|
||
|
||
图表来源
|
||
- [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7)
|
||
- [internal/repository/brand.go:12-51](file://internal/repository/brand.go#L12-L51)
|
||
|
||
章节来源
|
||
- [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7)
|
||
- [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51)
|
||
|
||
### Model 数据模型
|
||
- 设计理念
|
||
- 型号实体承载品牌名、型号名及可选属性(形态、设备类型、来源、等价键),并记录创建时间。
|
||
- 字段定义与约束
|
||
- id:整数,主键,自增。
|
||
- brandName:字符串,非空,与品牌维度关联。
|
||
- name:字符串,非空,型号名。
|
||
- form、rig、source、eqKey:字符串(指针),可空,表示形态、设备类型、来源、等价键。
|
||
- createAt:时间戳,非空,记录创建时间。
|
||
- 业务含义
|
||
- 作为核心产品维度,支持按品牌或型号名检索,可为空的扩展属性满足多样化设备描述。
|
||
- 数据库映射
|
||
- 表名:model。
|
||
- 字段:id、brand_name、name、form、rig、source、eq_key、create_at。
|
||
- 约束:唯一索引 (brand_name, name),保证同品牌下型号名唯一。
|
||
- ORM 映射配置
|
||
- 使用 sql.NullString 扫描可空列,再转换为指针字符串,避免零值歧义。
|
||
- JSON 标签用于序列化输出,可空字段支持 omitempty。
|
||
- 验证与序列化
|
||
- 无显式校验逻辑,依赖数据库约束与上层参数清洗。
|
||
- JSON 标签用于序列化输出。
|
||
- 查询流程
|
||
- 支持按品牌名精确匹配或按型号名模糊匹配,返回 []Model 列表。
|
||
- 默认返回空切片而非 nil,便于前端处理。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class Model {
|
||
+int id
|
||
+string brandName
|
||
+string name
|
||
+*string form
|
||
+*string rig
|
||
+*string source
|
||
+*string eqKey
|
||
+time createAt
|
||
}
|
||
class ModelRepository {
|
||
-db *sql.DB
|
||
+List(ctx, brandName, modelName) []Model
|
||
}
|
||
ModelRepository --> Model : "返回"
|
||
```
|
||
|
||
图表来源
|
||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||
- [internal/repository/model.go:12-95](file://internal/repository/model.go#L12-L95)
|
||
- [sql/model.sql:24-35](file://sql/model.sql#L24-L35)
|
||
|
||
章节来源
|
||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||
- [internal/repository/model.go:20-95](file://internal/repository/model.go#L20-L95)
|
||
- [sql/model.sql:24-35](file://sql/model.sql#L24-L35)
|
||
|
||
### 处理器与序列化机制
|
||
- 统一响应体
|
||
- 统一响应体包含 code、message、data 字段,便于前端统一处理。
|
||
- 可选 Base64 编码
|
||
- 支持通过 base64Resp 参数控制是否对 JSON 响应进行自定义 Base64 编码。
|
||
- 自定义映射表将标准 Base64 字符集映射为更紧凑的字符集,减少体积。
|
||
- 错误处理
|
||
- 处理器捕获仓库层错误,记录日志并通过统一响应体返回内部错误。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as "客户端"
|
||
participant H as "ModelHandler"
|
||
participant Repo as "ModelRepository"
|
||
participant DB as "数据库"
|
||
participant Enc as "编码层"
|
||
C->>H : "GET /audio/getModel?brandName=...&modelName=...&base64Resp=..."
|
||
H->>Repo : "List(brandName, modelName)"
|
||
Repo->>DB : "根据条件查询"
|
||
DB-->>Repo : "结果集"
|
||
Repo-->>H : "[]Model"
|
||
alt "base64Resp=true"
|
||
H->>Enc : "EncodeJSON([]Model)"
|
||
Enc-->>H : "Base64 字符串"
|
||
H-->>C : "200 OK + Base64"
|
||
else "默认"
|
||
H-->>C : "200 OK + JSON"
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||
- [internal/repository/model.go:20-95](file://internal/repository/model.go#L20-L95)
|
||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||
|
||
章节来源
|
||
- [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50)
|
||
- [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||
- [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||
|
||
### 查询与过滤逻辑
|
||
- Brand 查询
|
||
- 支持按品牌名模糊匹配,使用 LIKE 并按名称升序排列。
|
||
- Model 查询
|
||
- 优先按品牌名精确匹配;若为空则按型号名模糊匹配;否则返回空切片。
|
||
- 扫描时将 sql.NullString 转换为指针字符串,避免零值歧义。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["进入 List"]) --> Trim["去除前后空白"]
|
||
Trim --> CheckBrand{"brandName 是否非空?"}
|
||
CheckBrand --> |是| QueryBrand["按品牌名精确匹配"]
|
||
CheckBrand --> |否| CheckModel{"modelName 是否非空?"}
|
||
CheckModel --> |是| QueryModel["按型号名模糊匹配"]
|
||
CheckModel --> |否| ReturnEmpty["返回空切片"]
|
||
QueryBrand --> Exec["执行查询并扫描"]
|
||
QueryModel --> Exec
|
||
Exec --> End(["返回结果"])
|
||
ReturnEmpty --> End
|
||
```
|
||
|
||
图表来源
|
||
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
|
||
- [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51)
|
||
|
||
章节来源
|
||
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
|
||
- [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51)
|
||
|
||
## 依赖分析
|
||
- 层间耦合
|
||
- Handler 依赖 Repository;Repository 依赖 sql.DB;Model 为纯数据结构。
|
||
- 统一响应体与编码层被 Handler 调用,降低重复逻辑。
|
||
- 外部依赖
|
||
- 数据库:MySQL,通过 sql.DB 访问。
|
||
- 日志:zap。
|
||
- Web 框架:Gin。
|
||
- 搜索:Meilisearch(ModelListHandler)。
|
||
- 缓存:Redis(Device 相关处理器)。
|
||
- 潜在循环依赖
|
||
- 当前结构清晰,无循环导入迹象。
|
||
|
||
```mermaid
|
||
graph LR
|
||
H_Brand["BrandHandler"] --> Repo_Brand["BrandRepository"]
|
||
H_Model["ModelHandler"] --> Repo_Model["ModelRepository"]
|
||
H_ModelList["ModelListHandler"] --> Search["Meilisearch 客户端"]
|
||
Repo_Brand --> DB["sql.DB"]
|
||
Repo_Model --> DB
|
||
H_Brand --> Resp["统一响应体"]
|
||
H_Model --> Resp
|
||
H_ModelList --> Resp
|
||
H_Brand --> Encode["Base64 编码"]
|
||
H_Model --> Encode
|
||
H_ModelList --> Encode
|
||
```
|
||
|
||
图表来源
|
||
- [internal/handler/brand.go:14-50](file://internal/handler/brand.go#L14-L50)
|
||
- [internal/handler/model.go:14-51](file://internal/handler/model.go#L14-L51)
|
||
- [internal/handler/model_list.go:14-57](file://internal/handler/model_list.go#L14-L57)
|
||
- [internal/repository/brand.go:12-51](file://internal/repository/brand.go#L12-L51)
|
||
- [internal/repository/model.go:12-95](file://internal/repository/model.go#L12-L95)
|
||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||
|
||
章节来源
|
||
- [internal/router/router.go:14-42](file://internal/router/router.go#L14-L42)
|
||
- [internal/config/database.go:17-72](file://internal/config/database.go#L17-L72)
|
||
|
||
## 性能考虑
|
||
- 查询优化
|
||
- Model 表对 (brand_name, name) 建有唯一索引,有利于去重与快速定位。
|
||
- 查询时优先按品牌名匹配,减少 LIKE 的范围。
|
||
- 扫描与内存
|
||
- 使用 sql.NullString 扫描可空列,避免零值歧义;转换为指针字符串减少冗余存储。
|
||
- 编码策略
|
||
- 可选的自定义 Base64 编码可降低响应体积,适合大列表传输场景。
|
||
- 并发与超时
|
||
- 服务器设置读写超时与优雅关闭,保障稳定性。
|
||
|
||
章节来源
|
||
- [sql/model.sql:34-35](file://sql/model.sql#L34-L35)
|
||
- [internal/repository/model.go:63-95](file://internal/repository/model.go#L63-L95)
|
||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||
- [cmd/server/main.go:66-95](file://cmd/server/main.go#L66-L95)
|
||
|
||
## 故障排查指南
|
||
- 常见问题
|
||
- 数据库连接失败:检查环境变量与配置加载逻辑。
|
||
- 查询无结果:确认查询参数是否为空或大小写敏感;Model 查询默认返回空切片而非 nil。
|
||
- 编码异常:确认 base64Resp 参数与 JSON 序列化是否成功。
|
||
- 排查步骤
|
||
- 查看日志:处理器记录错误日志,统一响应体返回错误码。
|
||
- 核对数据库:确认表结构与索引是否存在。
|
||
- 验证参数:确认查询参数是否符合预期。
|
||
|
||
章节来源
|
||
- [internal/config/database.go:57-72](file://internal/config/database.go#L57-L72)
|
||
- [internal/handler/brand.go:31-35](file://internal/handler/brand.go#L31-L35)
|
||
- [internal/handler/model.go:33-36](file://internal/handler/model.go#L33-L36)
|
||
- [internal/handler/model_list.go:39-42](file://internal/handler/model_list.go#L39-L42)
|
||
- [internal/response/response.go:30-37](file://internal/response/response.go#L30-L37)
|
||
|
||
## 结论
|
||
本项目的数据模型设计简洁明确:Brand 与 Model 分别承担品牌与型号的维度,通过仓库层的原生 SQL 访问实现高效查询;处理器层统一响应与可选编码,提升传输效率与前端体验。数据库层面通过唯一索引与合理字段设计保障一致性与性能。建议在后续迭代中引入显式的校验与转换层,增强健壮性与可维护性。
|
||
|
||
## 附录
|
||
|
||
### 数据库表结构与模型映射对照
|
||
- 表:model
|
||
- 字段:id(主键)、brand_name、name、form、rig、source、eq_key、create_at。
|
||
- 约束:唯一索引 (brand_name, name)。
|
||
- 映射关系
|
||
- Model.id ↔ model.id
|
||
- Model.brandName ↔ model.brand_name
|
||
- Model.name ↔ model.name
|
||
- Model.form ↔ model.form
|
||
- Model.rig ↔ model.rig
|
||
- Model.source ↔ model.source
|
||
- Model.eqKey ↔ model.eq_key
|
||
- Model.createAt ↔ model.create_at
|
||
|
||
章节来源
|
||
- [sql/model.sql:24-35](file://sql/model.sql#L24-L35)
|
||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||
|
||
### 请求与响应示例(路径参考)
|
||
- 获取品牌列表
|
||
- 路由:/audio/getBrand
|
||
- 方法:GET
|
||
- 参数:brandName(可选),base64Resp(可选)
|
||
- 返回:[]Brand 或 Base64 编码后的 JSON
|
||
- 参考路径:[internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50)
|
||
- 获取型号列表
|
||
- 路由:/audio/getModel
|
||
- 方法:GET
|
||
- 参数:brandName(可选)、modelName(可选)、base64Resp(可选)
|
||
- 返回:[]Model 或 Base64 编码后的 JSON
|
||
- 参考路径:[internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||
- 搜索模型列表
|
||
- 路由:/audio/modelList
|
||
- 方法:GET
|
||
- 参数:key(必需)、count(可选)、base64Resp(可选)
|
||
- 返回:[]Model 或 Base64 编码后的 JSON
|
||
- 参考路径:[internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||
|
||
章节来源
|
||
- [internal/router/router.go:32-38](file://internal/router/router.go#L32-L38)
|
||
- [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50)
|
||
- [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||
- [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||
|
||
### 最佳实践建议
|
||
- 模型扩展
|
||
- 引入显式的校验与转换层,如参数清洗、长度限制、正则校验等。
|
||
- 对可空字段提供默认值策略,避免前端空值判断复杂化。
|
||
- 版本管理与向后兼容
|
||
- 通过 API 版本号(如 /api/v1)隔离变更;新增字段采用可选策略,保持旧字段必填。
|
||
- 对于破坏性变更,提供迁移脚本与双写策略。
|
||
- 性能优化
|
||
- 为高频查询字段建立索引;避免 SELECT *,仅选择必要字段。
|
||
- 对大列表启用可选 Base64 编码;结合分页与缓存策略。
|
||
- 错误处理与可观测性
|
||
- 统一错误码与消息格式;记录关键链路日志;对数据库与外部服务增加超时与重试。 |