306 lines
13 KiB
Markdown
306 lines
13 KiB
Markdown
|
|
# 材质删除
|
|||
|
|
|
|||
|
|
<cite>
|
|||
|
|
**本文引用的文件**
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go)
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go)
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go)
|
|||
|
|
- [internal/service/texture_service_test.go](file://internal/service/texture_service_test.go)
|
|||
|
|
</cite>
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
1. [简介](#简介)
|
|||
|
|
2. [项目结构](#项目结构)
|
|||
|
|
3. [核心组件](#核心组件)
|
|||
|
|
4. [架构总览](#架构总览)
|
|||
|
|
5. [详细组件分析](#详细组件分析)
|
|||
|
|
6. [依赖分析](#依赖分析)
|
|||
|
|
7. [性能考虑](#性能考虑)
|
|||
|
|
8. [故障排查指南](#故障排查指南)
|
|||
|
|
9. [结论](#结论)
|
|||
|
|
|
|||
|
|
## 简介
|
|||
|
|
本专项文档聚焦“材质删除”API,围绕删除操作的权限验证机制展开,结合服务层与仓储层的实现,说明删除流程、成功响应、错误场景,以及删除对数据库记录的影响(软删除)与关联数据处理(收藏关系)。同时基于测试用例,确认删除权限校验逻辑与行为一致性。
|
|||
|
|
|
|||
|
|
## 项目结构
|
|||
|
|
与材质删除相关的代码分布在以下模块:
|
|||
|
|
- 路由注册:定义DELETE /api/v1/texture/:id接口
|
|||
|
|
- 处理器:解析参数、鉴权、调用服务层并返回响应
|
|||
|
|
- 服务层:执行业务规则(权限校验、存在性校验)、调用仓储层
|
|||
|
|
- 仓储层:执行数据库操作(软删除)
|
|||
|
|
- 数据模型:定义材质实体、收藏关系、下载日志等
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
Routes["路由注册<br/>routes.go"] --> Handler["处理器<br/>texture_handler.go"]
|
|||
|
|
Handler --> Service["服务层<br/>texture_service.go"]
|
|||
|
|
Service --> Repo["仓储层<br/>texture_repository.go"]
|
|||
|
|
Repo --> Model["数据模型<br/>texture.go"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go#L42-L61)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go#L42-L61)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
|
|||
|
|
## 核心组件
|
|||
|
|
- 路由与鉴权
|
|||
|
|
- DELETE /api/v1/texture/:id 由处理器绑定,使用鉴权中间件,要求携带有效令牌。
|
|||
|
|
- 处理器
|
|||
|
|
- 解析路径参数(材质ID),从上下文提取当前用户ID,调用服务层执行删除,并按错误码返回相应HTTP状态与响应体。
|
|||
|
|
- 服务层
|
|||
|
|
- 校验材质存在性;校验删除权限(仅上传者可删);调用仓储层执行软删除。
|
|||
|
|
- 仓储层
|
|||
|
|
- 将材质记录的status字段置为-1,实现软删除。
|
|||
|
|
- 数据模型
|
|||
|
|
- 材质实体包含UploaderID、Status等字段;收藏关系通过user_texture_favorites表维护。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go#L42-L61)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
|
|||
|
|
## 架构总览
|
|||
|
|
下图展示从客户端到数据库的完整调用链路,包括鉴权、参数解析、权限校验、软删除与响应返回。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant C as "客户端"
|
|||
|
|
participant R as "路由(routes.go)"
|
|||
|
|
participant H as "处理器(texture_handler.go)"
|
|||
|
|
participant S as "服务层(texture_service.go)"
|
|||
|
|
participant P as "仓储层(texture_repository.go)"
|
|||
|
|
participant D as "数据库"
|
|||
|
|
C->>R : "DELETE /api/v1/texture/ : id"
|
|||
|
|
R->>H : "进入处理器"
|
|||
|
|
H->>H : "解析路径参数/校验JWT"
|
|||
|
|
H->>S : "service.DeleteTexture(db, textureID, uploaderID)"
|
|||
|
|
S->>P : "FindTextureByID(textureID)"
|
|||
|
|
P-->>S : "返回材质或nil"
|
|||
|
|
alt "材质不存在"
|
|||
|
|
S-->>H : "返回错误:材质不存在"
|
|||
|
|
H-->>C : "403 错误响应"
|
|||
|
|
else "材质存在"
|
|||
|
|
S->>S : "校验 uploaderID == 请求者ID"
|
|||
|
|
alt "非上传者"
|
|||
|
|
S-->>H : "返回错误:无权删除此材质"
|
|||
|
|
H-->>C : "403 错误响应"
|
|||
|
|
else "上传者本人"
|
|||
|
|
S->>P : "DeleteTexture(textureID)"
|
|||
|
|
P->>D : "UPDATE textures SET status=-1 WHERE id=..."
|
|||
|
|
D-->>P : "OK"
|
|||
|
|
P-->>S : "OK"
|
|||
|
|
S-->>H : "OK"
|
|||
|
|
H-->>C : "200 成功响应"
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go#L42-L61)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
|
|||
|
|
## 详细组件分析
|
|||
|
|
|
|||
|
|
### 删除API请求流程与权限验证
|
|||
|
|
- 路由与鉴权
|
|||
|
|
- DELETE /api/v1/texture/:id 由处理器绑定,使用鉴权中间件,要求携带有效令牌。
|
|||
|
|
- 参数解析与鉴权
|
|||
|
|
- 处理器从路径参数解析材质ID,从上下文提取当前用户ID;若缺失则返回未授权。
|
|||
|
|
- 权限验证
|
|||
|
|
- 服务层先查询材质是否存在且未被软删除;
|
|||
|
|
- 再校验请求者ID与材质的UploaderID一致,否则返回无权删除。
|
|||
|
|
- 执行删除
|
|||
|
|
- 通过仓储层将材质记录的status字段置为-1,完成软删除。
|
|||
|
|
- 响应
|
|||
|
|
- 成功返回200与通用成功响应体;错误返回403及错误信息。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
Start(["开始"]) --> Parse["解析路径参数<br/>获取材质ID"]
|
|||
|
|
Parse --> Auth{"JWT鉴权通过?"}
|
|||
|
|
Auth --> |否| Resp401["返回401 未授权"]
|
|||
|
|
Auth --> |是| Load["查询材质记录"]
|
|||
|
|
Load --> Exists{"是否存在且未软删除?"}
|
|||
|
|
Exists --> |否| Resp403a["返回403 材质不存在/已删除"]
|
|||
|
|
Exists --> |是| Perm{"请求者ID==上传者ID?"}
|
|||
|
|
Perm --> |否| Resp403b["返回403 无权删除此材质"]
|
|||
|
|
Perm --> |是| SoftDel["软删除:设置status=-1"]
|
|||
|
|
SoftDel --> Resp200["返回200 成功"]
|
|||
|
|
Resp401 --> End(["结束"])
|
|||
|
|
Resp403a --> End
|
|||
|
|
Resp403b --> End
|
|||
|
|
Resp200 --> End
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go#L42-L61)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
|
|||
|
|
### 权限验证机制
|
|||
|
|
- 上传者身份判定
|
|||
|
|
- 服务层比较请求者的用户ID与材质记录中的UploaderID,仅当两者相等时才允许删除。
|
|||
|
|
- 存在性与状态校验
|
|||
|
|
- 查询材质时会忽略status=-1的记录(软删除),因此若返回nil,即视为“不存在”。
|
|||
|
|
- 测试覆盖
|
|||
|
|
- 单元测试包含“删除权限检查”的用例,验证相同ID允许删除、不同ID拒绝删除的行为。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/service/texture_service_test.go](file://internal/service/texture_service_test.go#L315-L345)
|
|||
|
|
|
|||
|
|
### 删除API的成功响应与错误情况
|
|||
|
|
- 成功响应
|
|||
|
|
- HTTP 200,返回通用成功响应体(无额外数据)。
|
|||
|
|
- 常见错误
|
|||
|
|
- 401 未授权:缺少或无效的JWT令牌。
|
|||
|
|
- 400 参数错误:材质ID格式非法。
|
|||
|
|
- 403 无权删除:请求者非材质上传者。
|
|||
|
|
- 403 材质不存在:目标材质不存在或已被软删除。
|
|||
|
|
- 处理器侧错误分支
|
|||
|
|
- 参数解析失败返回400;
|
|||
|
|
- 服务层返回错误时统一转换为403(无权删除/不存在)。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
|
|||
|
|
### 数据库记录影响与关联数据处理
|
|||
|
|
- 删除策略
|
|||
|
|
- 采用软删除:将textures表的status字段置为-1,不物理移除记录。
|
|||
|
|
- 影响范围
|
|||
|
|
- 材质记录仍保留,便于审计与历史追踪;
|
|||
|
|
- 查询接口(如获取详情、搜索、我的材质)均会忽略status=-1的记录。
|
|||
|
|
- 关联数据
|
|||
|
|
- 收藏关系:删除操作不直接清理user_texture_favorites表中的收藏记录;
|
|||
|
|
- 若需清理收藏,应在业务层面另行设计或在仓储层扩展软删除时级联处理(当前实现未体现)。
|
|||
|
|
- 下载日志
|
|||
|
|
- 删除操作不涉及texture_download_logs表的清理。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L66-L79)
|
|||
|
|
|
|||
|
|
### 类图(代码级)
|
|||
|
|
```mermaid
|
|||
|
|
classDiagram
|
|||
|
|
class Texture {
|
|||
|
|
+int64 id
|
|||
|
|
+int64 uploader_id
|
|||
|
|
+string name
|
|||
|
|
+string description
|
|||
|
|
+TextureType type
|
|||
|
|
+string url
|
|||
|
|
+string hash
|
|||
|
|
+int size
|
|||
|
|
+bool is_public
|
|||
|
|
+int download_count
|
|||
|
|
+int favorite_count
|
|||
|
|
+bool is_slim
|
|||
|
|
+int16 status
|
|||
|
|
+time created_at
|
|||
|
|
+time updated_at
|
|||
|
|
}
|
|||
|
|
class UserTextureFavorite {
|
|||
|
|
+int64 id
|
|||
|
|
+int64 user_id
|
|||
|
|
+int64 texture_id
|
|||
|
|
+time created_at
|
|||
|
|
}
|
|||
|
|
class TextureDownloadLog {
|
|||
|
|
+int64 id
|
|||
|
|
+int64 texture_id
|
|||
|
|
+*int64 user_id
|
|||
|
|
+string ip_address
|
|||
|
|
+string user_agent
|
|||
|
|
+time created_at
|
|||
|
|
}
|
|||
|
|
Texture --> UserTextureFavorite : "收藏关系"
|
|||
|
|
Texture --> TextureDownloadLog : "下载日志"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go#L16-L35)
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go#L42-L57)
|
|||
|
|
- [internal/model/texture.go](file://internal/model/texture.go#L60-L71)
|
|||
|
|
|
|||
|
|
## 依赖分析
|
|||
|
|
- 组件耦合
|
|||
|
|
- 处理器依赖服务层;服务层依赖仓储层;仓储层依赖数据库访问工具。
|
|||
|
|
- 关键依赖链
|
|||
|
|
- 路由 -> 处理器 -> 服务层 -> 仓储层 -> 数据库
|
|||
|
|
- 可能的循环依赖
|
|||
|
|
- 当前文件间未发现循环导入;各层职责清晰,符合分层架构。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
Routes["routes.go"] --> Handler["texture_handler.go"]
|
|||
|
|
Handler --> Service["texture_service.go"]
|
|||
|
|
Service --> Repo["texture_repository.go"]
|
|||
|
|
Repo --> DB["数据库"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go#L42-L61)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/handler/routes.go](file://internal/handler/routes.go#L42-L61)
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
- [internal/repository/texture_repository.go](file://internal/repository/texture_repository.go#L126-L130)
|
|||
|
|
|
|||
|
|
## 性能考虑
|
|||
|
|
- 查询与软删除
|
|||
|
|
- 删除前的查询与软删除均为单记录操作,复杂度低。
|
|||
|
|
- 索引与过滤
|
|||
|
|
- 材质查询通常按UploaderID、状态、公开性等条件过滤,建议确保相关列具备索引以提升查询效率。
|
|||
|
|
- 批量与事务
|
|||
|
|
- 当前删除为单条记录操作,无需事务;若未来扩展批量删除,需评估事务边界与回滚策略。
|
|||
|
|
|
|||
|
|
## 故障排查指南
|
|||
|
|
- 401 未授权
|
|||
|
|
- 检查请求头Authorization是否携带有效JWT;确认中间件已正确注入user_id。
|
|||
|
|
- 400 参数错误
|
|||
|
|
- 检查路径参数id是否为合法整数。
|
|||
|
|
- 403 无权删除
|
|||
|
|
- 确认当前用户ID与材质记录的UploaderID一致;核对服务层权限校验逻辑。
|
|||
|
|
- 403 材质不存在
|
|||
|
|
- 确认材质ID有效且未被软删除;检查仓储层查询是否正确忽略status=-1。
|
|||
|
|
- 日志定位
|
|||
|
|
- 处理器与服务层均记录错误日志,可据此快速定位问题。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [internal/handler/texture_handler.go](file://internal/handler/texture_handler.go#L371-L419)
|
|||
|
|
- [internal/service/texture_service.go](file://internal/service/texture_service.go#L143-L160)
|
|||
|
|
|
|||
|
|
## 结论
|
|||
|
|
- 权限验证严格:仅上传者可删除材质,服务层明确校验请求者ID与UploaderID一致性。
|
|||
|
|
- 删除策略为软删除:通过status字段标记删除,不破坏历史数据与关联完整性。
|
|||
|
|
- 错误处理清晰:处理器将服务层错误映射为403,配合日志便于排障。
|
|||
|
|
- 关联清理:当前实现未清理收藏关系,如需可在业务层补充或扩展仓储层软删除逻辑。
|