# 材质API **本文引用的文件** - [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) - [upload_service.go](file://internal/service/upload_service.go) - [minio.go](file://pkg/storage/minio.go) - [auth.go](file://internal/middleware/auth.go) - [texture_service_test.go](file://internal/service/texture_service_test.go) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖分析](#依赖分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件面向“材质管理API”的使用者与维护者,系统性梳理材质的搜索、上传、创建、更新、删除、收藏及分页查询能力。基于路由组 /api/v1/texture 的公开与认证两类访问模式,详细说明各端点的行为、参数、响应与错误处理,并深入解析生成上传URL的流程、材质元数据创建、分页查询策略以及收藏功能的实现细节。同时解释材质与用户的关系及权限控制机制,帮助读者快速上手并正确集成。 ## 项目结构 - 路由注册集中在路由处理器中,按组划分公开与认证两类接口。 - 处理器负责参数校验、鉴权、调用服务层并返回统一响应。 - 服务层封装业务规则(如权限校验、分页边界、收藏增删计数)。 - 仓储层负责数据库查询与写入(含软删除、计数更新、收藏关联)。 - 模型层定义材质、收藏、下载日志等实体及其索引。 - 上传服务与存储客户端负责生成预签名上传URL与对象命名策略。 - 中间件提供JWT认证与可选认证能力。 ```mermaid graph TB subgraph "HTTP层" R["路由注册
routes.go"] H["处理器
texture_handler.go"] end subgraph "服务层" S["服务
texture_service.go"] end subgraph "仓储层" REPO["仓储
texture_repository.go"] end subgraph "模型层" M["模型
texture.go"] end subgraph "上传与存储" U["上传服务
upload_service.go"] ST["存储客户端
minio.go"] end subgraph "鉴权" A["认证中间件
auth.go"] end R --> H H --> A H --> S S --> REPO REPO --> M H --> U U --> ST ``` 图表来源 - [routes.go](file://internal/handler/routes.go#L42-L61) - [texture_handler.go](file://internal/handler/texture_handler.go#L1-L600) - [texture_service.go](file://internal/service/texture_service.go#L1-L252) - [texture_repository.go](file://internal/repository/texture_repository.go#L1-L232) - [texture.go](file://internal/model/texture.go#L1-L77) - [upload_service.go](file://internal/service/upload_service.go#L1-L161) - [minio.go](file://pkg/storage/minio.go#L1-L121) - [auth.go](file://internal/middleware/auth.go#L1-L79) 章节来源 - [routes.go](file://internal/handler/routes.go#L42-L61) ## 核心组件 - 路由与鉴权 - 公开端点:GET /api/v1/texture、GET /api/v1/texture/{id} - 认证端点:POST /api/v1/texture/upload-url、POST /api/v1/texture、PUT /api/v1/texture/{id}、DELETE /api/v1/texture/{id}、POST /api/v1/texture/{id}/favorite、GET /api/v1/texture/my、GET /api/v1/texture/favorites - 认证中间件要求 Authorization: Bearer ,通过后将用户信息注入上下文 - 数据模型 - 材质实体包含上传者ID、名称、描述、类型、URL、哈希、大小、公开状态、下载/收藏计数、是否细臂、状态、时间戳等;并关联上传者 - 收藏关联表 user_texture_favorites 记录用户与材质的收藏关系 - 下载日志表 texture_download_logs 记录下载行为 - 上传与存储 - 生成预签名POST URL,限定文件类型、大小范围与过期时间,对象路径按用户与材质类型组织 - 服务与仓储 - 提供搜索、分页、权限校验、收藏切换、软删除、计数更新等业务逻辑 - 仓储实现分页查询、总数统计、软删除、收藏增删与计数更新 章节来源 - [routes.go](file://internal/handler/routes.go#L42-L61) - [texture.go](file://internal/model/texture.go#L1-L77) - [upload_service.go](file://internal/service/upload_service.go#L1-L161) - [texture_service.go](file://internal/service/texture_service.go#L1-L252) - [texture_repository.go](file://internal/repository/texture_repository.go#L1-L232) - [auth.go](file://internal/middleware/auth.go#L1-L79) ## 架构总览 下图展示从HTTP请求到数据库与存储的关键交互路径,涵盖公开搜索、认证上传与创建、权限校验、收藏与分页等。 ```mermaid sequenceDiagram participant C as "客户端" participant R as "路由
routes.go" participant H as "处理器
texture_handler.go" participant A as "认证中间件
auth.go" participant S as "服务
texture_service.go" participant REPO as "仓储
texture_repository.go" participant M as "模型
texture.go" participant U as "上传服务
upload_service.go" participant ST as "存储客户端
minio.go" C->>R : 请求 /api/v1/texture/search R->>H : 调用 SearchTextures H->>S : 调用 SearchTextures(db, keyword, type, publicOnly, page, pageSize) S->>REPO : 查询并统计总数 REPO-->>S : 返回列表与总数 S-->>H : 返回结果 H-->>C : 200 + 分页数据 C->>R : 请求 /api/v1/texture/upload-url (认证) R->>A : 鉴权 A-->>R : 注入用户ID R->>H : 调用 GenerateTextureUploadURL H->>U : 生成预签名POST URL U->>ST : 生成POST策略与URL ST-->>U : 返回PostURL、FormData、FileURL U-->>H : 返回结果 H-->>C : 200 + 上传URL与过期时间 C->>R : 请求 /api/v1/texture (认证) R->>A : 鉴权 A-->>R : 注入用户ID R->>H : 调用 CreateTexture H->>S : 检查上传配额与创建材质 S->>REPO : 写入材质记录 REPO-->>S : 返回新记录 S-->>H : 返回材质信息 H-->>C : 200 + 材质详情 ``` 图表来源 - [routes.go](file://internal/handler/routes.go#L42-L61) - [texture_handler.go](file://internal/handler/texture_handler.go#L1-L600) - [auth.go](file://internal/middleware/auth.go#L1-L79) - [upload_service.go](file://internal/service/upload_service.go#L117-L160) - [minio.go](file://pkg/storage/minio.go#L82-L121) - [texture_service.go](file://internal/service/texture_service.go#L1-L252) - [texture_repository.go](file://internal/repository/texture_repository.go#L1-L232) - [texture.go](file://internal/model/texture.go#L1-L77) ## 详细组件分析 ### 路由与访问模式 - 公开访问 - GET /api/v1/texture:搜索材质(关键词、类型、公开筛选、分页) - GET /api/v1/texture/{id}:获取材质详情 - 认证访问 - POST /api/v1/texture/upload-url:生成材质上传URL(预签名POST) - POST /api/v1/texture:创建材质记录(文件已上传至存储) - PUT /api/v1/texture/{id}:更新材质(仅上传者可操作) - DELETE /api/v1/texture/{id}:删除材质(软删除,仅上传者可操作) - POST /api/v1/texture/{id}/favorite:切换收藏 - GET /api/v1/texture/my:获取当前用户上传的材质列表(分页) - GET /api/v1/texture/favorites:获取当前用户收藏的材质列表(分页) 章节来源 - [routes.go](file://internal/handler/routes.go#L42-L61) ### 生成上传URL流程 - 客户端向 POST /api/v1/texture/upload-url 发起请求,携带文件名与材质类型(SKIN/CAPE) - 处理器校验请求体、获取用户ID并调用上传服务 - 上传服务: - 校验文件名扩展名与类型 - 选择对应上传配置(大小范围、过期时间) - 解析存储桶名称(textures) - 生成对象名:user_{userID}/{textureTypeFolder}/{timestamp}_{originalFileName} - 生成预签名POST策略(含内容长度范围、过期时间),返回PostURL、FormData与最终访问URL - 客户端使用返回的PostURL与FormData直传到对象存储,成功后调用 POST /api/v1/texture 创建材质记录 ```mermaid flowchart TD Start(["开始"]) --> Bind["绑定请求体
文件名/类型"] Bind --> Validate["校验文件名与类型"] Validate --> Config["加载上传配置"] Config --> Bucket["解析存储桶名称"] Bucket --> ObjName["生成对象名
user_{id}/{type}/{ts}_{fileName}"] ObjName --> Policy["生成预签名POST策略"] Policy --> Result["返回PostURL/FormData/FileURL"] Result --> End(["结束"]) ``` 图表来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L18-L83) - [upload_service.go](file://internal/service/upload_service.go#L117-L160) - [minio.go](file://pkg/storage/minio.go#L82-L121) 章节来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L18-L83) - [upload_service.go](file://internal/service/upload_service.go#L117-L160) - [minio.go](file://pkg/storage/minio.go#L82-L121) ### 材质元数据创建 - 客户端上传完成后,向 POST /api/v1/texture 提交材质元数据(名称、描述、类型、URL、哈希、大小、公开状态、是否细臂) - 处理器: - 校验请求体 - 检查用户上传配额(默认最大100条) - 调用服务层创建材质记录(校验用户存在、去重哈希、转换类型、初始化默认值) - 写入数据库并返回材质信息 - 服务层: - 校验用户存在 - 哈希去重检查 - 类型转换(SKIN/CAPE) - 初始化状态、下载/收藏计数为0 - 仓储层: - 插入记录 章节来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L85-L172) - [texture_service.go](file://internal/service/texture_service.go#L12-L64) - [texture_repository.go](file://internal/repository/texture_repository.go#L9-L13) - [texture.go](file://internal/model/texture.go#L16-L35) ### 搜索与分页查询 - GET /api/v1/texture 支持: - keyword:关键词(名称/描述模糊匹配) - type:SKIN/CAPE - public_only:仅公开材质 - page/page_size:分页(最小1,最大100,默认20) - 服务层对分页参数进行边界修正,仓储层: - 若 public_only 为真,则过滤 is_public=true - 按 type 进行精确过滤 - 按 name/description 模糊匹配 - 统计总数并按创建时间倒序分页查询 - 返回统一分页响应(list、total、page、page_size、total_pages) 章节来源 - [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) ### 更新与删除 - PUT /api/v1/texture/{id}: - 仅材质上传者可更新 - 支持更新名称、描述、公开状态(可选字段) - 服务层按非空字段构建更新集合并执行 - DELETE /api/v1/texture/{id}: - 仅材质上传者可删除 - 采用软删除(status=-1),不影响历史下载/收藏计数 章节来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L293-L419) - [texture_service.go](file://internal/service/texture_service.go#L105-L160) - [texture_repository.go](file://internal/repository/texture_repository.go#L126-L131) ### 收藏功能 - POST /api/v1/texture/{id}/favorite: - 切换收藏状态(已收藏则取消,未收藏则添加) - 服务层先检查材质是否存在,再判断是否已收藏 - 成功后分别更新 user_texture_favorites 与 textures.favorite_count - 返回 is_favorited 结果 - GET /api/v1/texture/favorites: - 获取当前用户收藏的材质列表(分页,最小1,最大100,默认20) - 仓储层通过子查询定位收藏的材质ID,再查询并统计总数 章节来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L421-L471) - [texture_handler.go](file://internal/handler/texture_handler.go#L537-L599) - [texture_service.go](file://internal/service/texture_service.go#L189-L238) - [texture_repository.go](file://internal/repository/texture_repository.go#L159-L221) - [texture.go](file://internal/model/texture.go#L42-L57) ### 我的材质 - GET /api/v1/texture/my: - 获取当前用户上传的材质列表(分页,最小1,最大100,默认20) - 仓储层按 uploader_id 且 status!=-1 过滤,统计总数并分页查询 章节来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L473-L535) - [texture_service.go](file://internal/service/texture_service.go#L81-L91) - [texture_repository.go](file://internal/repository/texture_repository.go#L43-L69) ### 权限控制与用户关系 - 认证中间件要求 Authorization: Bearer ,并将用户ID、用户名、角色注入上下文 - 权限规则: - 仅上传者可更新/删除材质 - 仅登录用户可收藏/取消收藏 - 搜索公开材质时可匿名访问 - 上传URL生成与创建材质需登录 - 材质与用户: - 材质实体包含 uploader_id 字段,指向上传者 - 模型中定义了 Uploader 关联,便于返回上传者信息 章节来源 - [auth.go](file://internal/middleware/auth.go#L1-L79) - [texture_handler.go](file://internal/handler/texture_handler.go#L293-L419) - [texture.go](file://internal/model/texture.go#L16-L35) ## 依赖分析 - 处理器依赖: - 类型定义:请求/响应结构体(来自 internal/types/common.go) - 服务层:业务逻辑封装 - 存储服务:生成预签名URL - 服务层依赖: - 仓储层:数据库操作 - 模型层:实体定义 - 仓储层依赖: - 数据库连接与GORM - 模型层:实体与索引 - 上传服务依赖: - 存储客户端:生成POST策略与URL - 配置:上传大小范围、过期时间、SSL与Endpoint ```mermaid graph LR H["texture_handler.go"] --> T["types/common.go"] H --> S["texture_service.go"] S --> REPO["texture_repository.go"] REPO --> M["texture.go"] H --> U["upload_service.go"] U --> ST["minio.go"] H --> A["auth.go"] ``` 图表来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L1-L600) - [common.go](file://internal/types/common.go#L86-L191) - [texture_service.go](file://internal/service/texture_service.go#L1-L252) - [texture_repository.go](file://internal/repository/texture_repository.go#L1-L232) - [texture.go](file://internal/model/texture.go#L1-L77) - [upload_service.go](file://internal/service/upload_service.go#L1-L161) - [minio.go](file://pkg/storage/minio.go#L1-L121) - [auth.go](file://internal/middleware/auth.go#L1-L79) ## 性能考虑 - 分页参数边界 - 所有分页接口均对 page/page_size 进行边界约束(最小1,最大100,默认20),避免过大请求导致数据库压力 - 查询优化 - 搜索接口按 status=1 与可选 is_public、type、关键词进行过滤,建议在相关列建立索引以提升查询效率 - 分页查询按 created_at 倒序,结合索引可减少排序成本 - 计数更新 - 收藏/下载计数采用原子更新(UpdateColumn),降低并发冲突概率 - 上传URL - 预签名POST策略限制文件大小范围与过期时间,减少无效请求与存储压力 章节来源 - [texture_service.go](file://internal/service/texture_service.go#L81-L103) - [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112) - [texture_repository.go](file://internal/repository/texture_repository.go#L132-L151) ## 故障排查指南 - 认证失败 - 缺少Authorization头或格式不正确:返回401 - Token无效:返回401 - 参数错误 - 请求体绑定失败:返回400 - 无效的材质ID:返回400 - 权限不足 - 非上传者尝试更新/删除:返回403 - 业务异常 - 材质不存在:返回404 - 已达到上传数量上限:返回400 - 哈希重复:返回400 - 上传URL生成失败 - 文件名不合法、类型不支持、存储桶不存在、生成策略失败:返回400 - 搜索/分页异常 - 数据库查询失败:返回500 章节来源 - [texture_handler.go](file://internal/handler/texture_handler.go#L18-L83) - [texture_handler.go](file://internal/handler/texture_handler.go#L85-L172) - [texture_handler.go](file://internal/handler/texture_handler.go#L293-L419) - [texture_handler.go](file://internal/handler/texture_handler.go#L421-L471) - [texture_handler.go](file://internal/handler/texture_handler.go#L473-L599) - [texture_service.go](file://internal/service/texture_service.go#L12-L64) - [texture_service.go](file://internal/service/texture_service.go#L105-L160) - [texture_service.go](file://internal/service/texture_service.go#L189-L238) ## 结论 材质API围绕公开搜索与认证上传两条主线设计,通过严格的参数校验、权限控制与分页策略保障可用性与性能。上传流程采用预签名POST策略,既简化客户端实现又保证安全性。收藏与分页查询进一步完善了用户体验。建议在生产环境中为常用查询列建立索引,并结合监控与日志持续优化性能与稳定性。 ## 附录 ### API端点一览(公开与认证) - 公开 - GET /api/v1/texture:搜索材质(关键词、类型、公开筛选、分页) - GET /api/v1/texture/{id}:获取材质详情 - 认证 - POST /api/v1/texture/upload-url:生成材质上传URL(预签名POST) - POST /api/v1/texture:创建材质记录 - PUT /api/v1/texture/{id}:更新材质 - DELETE /api/v1/texture/{id}:删除材质 - POST /api/v1/texture/{id}/favorite:切换收藏 - GET /api/v1/texture/my:我的材质(分页) - GET /api/v1/texture/favorites:我的收藏(分页) 章节来源 - [routes.go](file://internal/handler/routes.go#L42-L61) ### 请求/响应要点 - 生成上传URL - 请求体:file_name、texture_type(SKIN/CAPE) - 响应体:post_url、form_data、texture_url、expires_in - 创建材质 - 请求体:name、description、type、url、hash、size、is_public、is_slim - 响应体:完整材质信息(含计数与时间戳) - 搜索 - 查询参数:keyword、type、public_only、page、page_size - 响应体:分页列表与总数 - 收藏 - 请求体:无 - 响应体:is_favorited - 我的材质/收藏 - 查询参数:page、page_size - 响应体:分页列表与总数 章节来源 - [common.go](file://internal/types/common.go#L86-L191) - [texture_handler.go](file://internal/handler/texture_handler.go#L18-L83) - [texture_handler.go](file://internal/handler/texture_handler.go#L85-L172) - [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291) - [texture_handler.go](file://internal/handler/texture_handler.go#L421-L471) - [texture_handler.go](file://internal/handler/texture_handler.go#L473-L599)