10 KiB
10 KiB
材质搜索
**本文引用的文件** - [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)目录
简介
本文件面向“材质搜索API”的使用与实现,围绕关键词搜索、材质类型过滤、公开性筛选与分页功能进行深入解析。基于仓库中的 SearchTextures 查询流程,解释关键词匹配(名称与描述)、类型过滤、公开状态筛选的实现细节,并结合分页测试用例说明分页参数的处理规则(page小于1时设为1,pageSize超过100时设为20)。同时提供请求示例、响应数据结构说明与错误处理机制,并解释搜索结果中上传者信息的预加载机制(Preload)及其对性能的影响。
项目结构
材质搜索API由三层协作完成:
- 路由层:注册 /api/v1/texture 的 GET 搜索接口
- 处理层:解析查询参数、调用服务层并返回分页响应
- 服务层:规范化分页参数、调用仓储层执行查询
- 仓储层:构建查询条件、统计总数、分页查询并预加载上传者信息
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"]
图表来源
章节来源
核心组件
- 路由注册:在 v1 组下将 GET /api/v1/texture 绑定到处理器 SearchTextures
- 处理器:读取 keyword、type、public_only、page、page_size 查询参数,调用服务层,转换为统一响应结构
- 服务层:对分页参数进行边界校正(page<1 设为1;pageSize<1 或 >100 设为20),再调用仓储层
- 仓储层:按状态=1 进行基础过滤;公开筛选、类型筛选、关键词模糊匹配;先 Count 再分页查询;使用 Preload 预加载上传者信息
章节来源
架构总览
下面以序列图展示一次完整搜索请求的调用链路:
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 + 分页响应
图表来源
详细组件分析
请求参数与处理规则
- 查询参数
- 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") 预加载关联用户信息,便于直接返回上传者字段
章节来源
数据模型与关联
- 材质模型包含上传者外键关联,仓储层通过 Preload 加载上传者信息
- 上传者信息在响应中以嵌套对象形式返回,便于前端直接显示
章节来源
响应数据结构
- 分页响应包含:
- list:结果数组(元素为材质信息)
- total:总条目数
- page:当前页码
- page_size:每页数量
- total_pages:总页数(由通用分页响应类型计算)
章节来源
错误处理机制
- 参数解析失败:返回 400 错误
- 服务内部错误:返回 500 错误
- 业务错误(如材质不存在等)在其他接口中体现,搜索接口主要返回 500 表示查询失败
章节来源
分页测试用例要点
- page<1 → 1
- pageSize<1 → 20
- pageSize>100 → 20
- 以上规则在服务层统一应用,确保查询稳定性
章节来源
依赖关系分析
- 路由层依赖处理器层
- 处理器层依赖服务层
- 服务层依赖仓储层
- 仓储层依赖数据库层
- 响应结构依赖通用分页类型
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
图表来源
性能考量
- 预加载上传者信息(Preload)会增加单次查询的 JOIN 数量,导致额外的网络往返与内存占用。建议:
- 在高频搜索场景中评估是否需要返回上传者信息;若不需要,可在仓储层移除 Preload
- 对搜索结果进行缓存(如 Redis)以减少重复 COUNT 与分页查询
- 为常用筛选维度建立合适索引(例如 idx_textures_public_type_status、idx_textures_download_count 等)
- 关键词模糊匹配使用 LIKE 百分号前缀可能导致索引失效,建议:
- 评估是否需要全文检索或倒排索引
- 对高并发场景考虑异步搜索或搜索引擎(如 Elasticsearch)
章节来源
故障排查指南
- 搜索无结果
- 检查 keyword 是否过短或包含特殊字符
- 确认 public_only 是否设置为 true 导致过滤掉私有材质
- 确认 type 是否正确传入(SKIN/CAPE)
- 分页异常
- page 小于1会被自动修正为1
- page_size 超过100会被修正为20
- 参数错误
- 确认查询参数类型与默认值是否符合预期
- 服务器错误
- 查看服务层日志,确认数据库连接与查询是否报错
章节来源
结论
材质搜索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
章节来源
响应示例
- 成功响应包含分页字段: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
章节来源