243 lines
10 KiB
Markdown
243 lines
10 KiB
Markdown
|
|
# 材质搜索
|
|||
|
|
|
|||
|
|
<cite>
|
|||
|
|
**本文引用的文件**
|
|||
|
|
- [routes.go](file://internal/handler/routes.go)
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go)
|
|||
|
|
- [texture_service.go](file://internal/service/texture_service.go)
|
|||
|
|
- [texture_repository.go](file://internal/repository/texture_repository.go)
|
|||
|
|
- [texture.go](file://internal/model/texture.go)
|
|||
|
|
- [common.go](file://internal/types/common.go)
|
|||
|
|
- [texture_service_test.go](file://internal/service/texture_service_test.go)
|
|||
|
|
</cite>
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
1. [简介](#简介)
|
|||
|
|
2. [项目结构](#项目结构)
|
|||
|
|
3. [核心组件](#核心组件)
|
|||
|
|
4. [架构总览](#架构总览)
|
|||
|
|
5. [详细组件分析](#详细组件分析)
|
|||
|
|
6. [依赖关系分析](#依赖关系分析)
|
|||
|
|
7. [性能考量](#性能考量)
|
|||
|
|
8. [故障排查指南](#故障排查指南)
|
|||
|
|
9. [结论](#结论)
|
|||
|
|
10. [附录](#附录)
|
|||
|
|
|
|||
|
|
## 简介
|
|||
|
|
本文件面向“材质搜索API”的使用与实现,围绕关键词搜索、材质类型过滤、公开性筛选与分页功能进行深入解析。基于仓库中的 SearchTextures 查询流程,解释关键词匹配(名称与描述)、类型过滤、公开状态筛选的实现细节,并结合分页测试用例说明分页参数的处理规则(page小于1时设为1,pageSize超过100时设为20)。同时提供请求示例、响应数据结构说明与错误处理机制,并解释搜索结果中上传者信息的预加载机制(Preload)及其对性能的影响。
|
|||
|
|
|
|||
|
|
## 项目结构
|
|||
|
|
材质搜索API由三层协作完成:
|
|||
|
|
- 路由层:注册 /api/v1/texture 的 GET 搜索接口
|
|||
|
|
- 处理层:解析查询参数、调用服务层并返回分页响应
|
|||
|
|
- 服务层:规范化分页参数、调用仓储层执行查询
|
|||
|
|
- 仓储层:构建查询条件、统计总数、分页查询并预加载上传者信息
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
Client["客户端"] --> Routes["路由: /api/v1/texture(GET)"]
|
|||
|
|
Routes --> Handler["处理器: SearchTextures"]
|
|||
|
|
Handler --> Service["服务: SearchTextures"]
|
|||
|
|
Service --> Repo["仓储: SearchTextures"]
|
|||
|
|
Repo --> DB["数据库"]
|
|||
|
|
Handler --> Resp["分页响应: list,total,page,page_size,total_pages"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [routes.go](file://internal/handler/routes.go#L43-L61)
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
- [texture_service.go](file://internal/service/texture_service.go#L93-L103)
|
|||
|
|
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [routes.go](file://internal/handler/routes.go#L43-L61)
|
|||
|
|
|
|||
|
|
## 核心组件
|
|||
|
|
- 路由注册:在 v1 组下将 GET /api/v1/texture 绑定到处理器 SearchTextures
|
|||
|
|
- 处理器:读取 keyword、type、public_only、page、page_size 查询参数,调用服务层,转换为统一响应结构
|
|||
|
|
- 服务层:对分页参数进行边界校正(page<1 设为1;pageSize<1 或 >100 设为20),再调用仓储层
|
|||
|
|
- 仓储层:按状态=1 进行基础过滤;公开筛选、类型筛选、关键词模糊匹配;先 Count 再分页查询;使用 Preload 预加载上传者信息
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
- [texture_service.go](file://internal/service/texture_service.go#L93-L103)
|
|||
|
|
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
|||
|
|
|
|||
|
|
## 架构总览
|
|||
|
|
下面以序列图展示一次完整搜索请求的调用链路:
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant C as "客户端"
|
|||
|
|
participant R as "路由"
|
|||
|
|
participant H as "处理器"
|
|||
|
|
participant S as "服务层"
|
|||
|
|
participant RE as "仓储层"
|
|||
|
|
participant D as "数据库"
|
|||
|
|
C->>R : GET /api/v1/texture?keyword=&type=&public_only=&page=&page_size=
|
|||
|
|
R->>H : 调用 SearchTextures
|
|||
|
|
H->>H : 解析查询参数<br/>keyword,type,public_only,page,page_size
|
|||
|
|
H->>S : SearchTextures(db, keyword, type, public_only, page, page_size)
|
|||
|
|
S->>S : 校正分页参数<br/>page<1→1;pageSize<1或>100→20
|
|||
|
|
S->>RE : SearchTextures(keyword, type, public_only, page, page_size)
|
|||
|
|
RE->>D : 构建查询条件(status=1)<br/>公开筛选(is_public=?)<br/>类型筛选(type=?)
|
|||
|
|
RE->>D : 关键词模糊匹配(name/description)<br/>Count统计总数
|
|||
|
|
RE->>D : 分页查询(Offset/Limit)<br/>Preload上传者信息
|
|||
|
|
D-->>RE : 结果集+总数
|
|||
|
|
RE-->>S : 返回结果集+总数
|
|||
|
|
S-->>H : 返回结果集+总数
|
|||
|
|
H-->>C : 200 + 分页响应
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [routes.go](file://internal/handler/routes.go#L43-L61)
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
- [texture_service.go](file://internal/service/texture_service.go#L93-L103)
|
|||
|
|
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
|||
|
|
|
|||
|
|
## 详细组件分析
|
|||
|
|
|
|||
|
|
### 请求参数与处理规则
|
|||
|
|
- 查询参数
|
|||
|
|
- keyword:关键词,支持名称与描述的模糊匹配
|
|||
|
|
- type:材质类型,可选 SKIN/CAPE
|
|||
|
|
- public_only:布尔值,仅返回公开材质
|
|||
|
|
- page:页码,默认1
|
|||
|
|
- page_size:每页数量,默认20
|
|||
|
|
- 参数边界校正(服务层)
|
|||
|
|
- page 小于1时设为1
|
|||
|
|
- page_size 小于1时设为20;大于100时也设为20
|
|||
|
|
- 类型与公开筛选
|
|||
|
|
- 类型为空字符串时不参与筛选
|
|||
|
|
- public_only 为真时追加 is_public=true 条件
|
|||
|
|
- 关键词匹配
|
|||
|
|
- 同时对 name 和 description 使用 LIKE 模糊匹配
|
|||
|
|
- 排序与分页
|
|||
|
|
- 默认按 created_at 降序排序
|
|||
|
|
- Offset=(page-1)*page_size,Limit=page_size
|
|||
|
|
- 预加载上传者信息
|
|||
|
|
- 使用 Preload("Uploader") 预加载关联用户信息,便于直接返回上传者字段
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
- [texture_service.go](file://internal/service/texture_service.go#L93-L103)
|
|||
|
|
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
|||
|
|
- [texture_service_test.go](file://internal/service/texture_service_test.go#L163-L215)
|
|||
|
|
|
|||
|
|
### 数据模型与关联
|
|||
|
|
- 材质模型包含上传者外键关联,仓储层通过 Preload 加载上传者信息
|
|||
|
|
- 上传者信息在响应中以嵌套对象形式返回,便于前端直接显示
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
|
|||
|
|
### 响应数据结构
|
|||
|
|
- 分页响应包含:
|
|||
|
|
- list:结果数组(元素为材质信息)
|
|||
|
|
- total:总条目数
|
|||
|
|
- page:当前页码
|
|||
|
|
- page_size:每页数量
|
|||
|
|
- total_pages:总页数(由通用分页响应类型计算)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [common.go](file://internal/types/common.go#L18-L25)
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
|
|||
|
|
### 错误处理机制
|
|||
|
|
- 参数解析失败:返回 400 错误
|
|||
|
|
- 服务内部错误:返回 500 错误
|
|||
|
|
- 业务错误(如材质不存在等)在其他接口中体现,搜索接口主要返回 500 表示查询失败
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
|
|||
|
|
### 分页测试用例要点
|
|||
|
|
- page<1 → 1
|
|||
|
|
- pageSize<1 → 20
|
|||
|
|
- pageSize>100 → 20
|
|||
|
|
- 以上规则在服务层统一应用,确保查询稳定性
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture_service_test.go](file://internal/service/texture_service_test.go#L163-L215)
|
|||
|
|
|
|||
|
|
## 依赖关系分析
|
|||
|
|
- 路由层依赖处理器层
|
|||
|
|
- 处理器层依赖服务层
|
|||
|
|
- 服务层依赖仓储层
|
|||
|
|
- 仓储层依赖数据库层
|
|||
|
|
- 响应结构依赖通用分页类型
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
Routes["routes.go"] --> Handler["texture_handler.go"]
|
|||
|
|
Handler --> Service["texture_service.go"]
|
|||
|
|
Service --> Repo["texture_repository.go"]
|
|||
|
|
Repo --> Model["texture.go"]
|
|||
|
|
Handler --> Types["common.go"]
|
|||
|
|
Service --> Types
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [routes.go](file://internal/handler/routes.go#L43-L61)
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
- [texture_service.go](file://internal/service/texture_service.go#L93-L103)
|
|||
|
|
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
|||
|
|
- [texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
- [common.go](file://internal/types/common.go#L18-L25)
|
|||
|
|
|
|||
|
|
## 性能考量
|
|||
|
|
- 预加载上传者信息(Preload)会增加单次查询的 JOIN 数量,导致额外的网络往返与内存占用。建议:
|
|||
|
|
- 在高频搜索场景中评估是否需要返回上传者信息;若不需要,可在仓储层移除 Preload
|
|||
|
|
- 对搜索结果进行缓存(如 Redis)以减少重复 COUNT 与分页查询
|
|||
|
|
- 为常用筛选维度建立合适索引(例如 idx_textures_public_type_status、idx_textures_download_count 等)
|
|||
|
|
- 关键词模糊匹配使用 LIKE 百分号前缀可能导致索引失效,建议:
|
|||
|
|
- 评估是否需要全文检索或倒排索引
|
|||
|
|
- 对高并发场景考虑异步搜索或搜索引擎(如 Elasticsearch)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
|||
|
|
- [texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
|
|||
|
|
## 故障排查指南
|
|||
|
|
- 搜索无结果
|
|||
|
|
- 检查 keyword 是否过短或包含特殊字符
|
|||
|
|
- 确认 public_only 是否设置为 true 导致过滤掉私有材质
|
|||
|
|
- 确认 type 是否正确传入(SKIN/CAPE)
|
|||
|
|
- 分页异常
|
|||
|
|
- page 小于1会被自动修正为1
|
|||
|
|
- page_size 超过100会被修正为20
|
|||
|
|
- 参数错误
|
|||
|
|
- 确认查询参数类型与默认值是否符合预期
|
|||
|
|
- 服务器错误
|
|||
|
|
- 查看服务层日志,确认数据库连接与查询是否报错
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
- [texture_service.go](file://internal/service/texture_service.go#L93-L103)
|
|||
|
|
- [texture_service_test.go](file://internal/service/texture_service_test.go#L163-L215)
|
|||
|
|
|
|||
|
|
## 结论
|
|||
|
|
材质搜索API通过清晰的三层职责划分,实现了关键词、类型与公开性三类筛选,并以稳健的分页参数校正保障了查询稳定性。预加载上传者信息提升了前端展示效率,但需关注其带来的性能成本。建议在生产环境中结合缓存与索引优化,进一步提升搜索吞吐与延迟表现。
|
|||
|
|
|
|||
|
|
## 附录
|
|||
|
|
|
|||
|
|
### 请求示例
|
|||
|
|
- 基础搜索(关键词)
|
|||
|
|
- GET /api/v1/texture?keyword=steve
|
|||
|
|
- 类型筛选
|
|||
|
|
- GET /api/v1/texture?type=SKIN
|
|||
|
|
- 公开性筛选
|
|||
|
|
- GET /api/v1/texture?public_only=true
|
|||
|
|
- 组合查询
|
|||
|
|
- GET /api/v1/texture?keyword=cape&type=CAPE&public_only=true&page=1&page_size=20
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
|||
|
|
|
|||
|
|
### 响应示例
|
|||
|
|
- 成功响应包含分页字段:list、total、page、page_size、total_pages
|
|||
|
|
- 每个材质项包含:id、uploader_id、name、description、type、url、hash、size、is_public、download_count、favorite_count、is_slim、status、created_at、updated_at
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [common.go](file://internal/types/common.go#L18-L25)
|
|||
|
|
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|