# 材质搜索 **本文引用的文件** - [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) ## 目录 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 : 解析查询参数
keyword,type,public_only,page,page_size H->>S : SearchTextures(db, keyword, type, public_only, page, page_size) S->>S : 校正分页参数
page<1→1;pageSize<1或>100→20 S->>RE : SearchTextures(keyword, type, public_only, page, page_size) RE->>D : 构建查询条件(status=1)
公开筛选(is_public=?)
类型筛选(type=?) RE->>D : 关键词模糊匹配(name/description)
Count统计总数 RE->>D : 分页查询(Offset/Limit)
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)