Files
backend/.qoder/repowiki/zh/content/API参考/材质API/材质API.md
lan a4b6c5011e
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
chore(git): 更新.gitignore以忽略新的本地文件
2025-11-30 08:33:17 +08:00

431 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 材质API
<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)
- [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)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向“材质管理API”的使用者与维护者系统性梳理材质的搜索、上传、创建、更新、删除、收藏及分页查询能力。基于路由组 /api/v1/texture 的公开与认证两类访问模式详细说明各端点的行为、参数、响应与错误处理并深入解析生成上传URL的流程、材质元数据创建、分页查询策略以及收藏功能的实现细节。同时解释材质与用户的关系及权限控制机制帮助读者快速上手并正确集成。
## 项目结构
- 路由注册集中在路由处理器中,按组划分公开与认证两类接口。
- 处理器负责参数校验、鉴权、调用服务层并返回统一响应。
- 服务层封装业务规则(如权限校验、分页边界、收藏增删计数)。
- 仓储层负责数据库查询与写入(含软删除、计数更新、收藏关联)。
- 模型层定义材质、收藏、下载日志等实体及其索引。
- 上传服务与存储客户端负责生成预签名上传URL与对象命名策略。
- 中间件提供JWT认证与可选认证能力。
```mermaid
graph TB
subgraph "HTTP层"
R["路由注册<br/>routes.go"]
H["处理器<br/>texture_handler.go"]
end
subgraph "服务层"
S["服务<br/>texture_service.go"]
end
subgraph "仓储层"
REPO["仓储<br/>texture_repository.go"]
end
subgraph "模型层"
M["模型<br/>texture.go"]
end
subgraph "上传与存储"
U["上传服务<br/>upload_service.go"]
ST["存储客户端<br/>minio.go"]
end
subgraph "鉴权"
A["认证中间件<br/>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 <token>,通过后将用户信息注入上下文
- 数据模型
- 材质实体包含上传者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 "路由<br/>routes.go"
participant H as "处理器<br/>texture_handler.go"
participant A as "认证中间件<br/>auth.go"
participant S as "服务<br/>texture_service.go"
participant REPO as "仓储<br/>texture_repository.go"
participant M as "模型<br/>texture.go"
participant U as "上传服务<br/>upload_service.go"
participant ST as "存储客户端<br/>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["绑定请求体<br/>文件名/类型"]
Bind --> Validate["校验文件名与类型"]
Validate --> Config["加载上传配置"]
Config --> Bucket["解析存储桶名称"]
Bucket --> ObjName["生成对象名<br/>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关键词名称/描述模糊匹配)
- typeSKIN/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 <token>并将用户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_typeSKIN/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)