# 材质删除 **本文引用的文件** - [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) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖分析](#依赖分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) ## 简介 本专项文档聚焦“材质删除”API,围绕删除操作的权限验证机制展开,结合服务层与仓储层的实现,说明删除流程、成功响应、错误场景,以及删除对数据库记录的影响(软删除)与关联数据处理(收藏关系)。同时基于测试用例,确认删除权限校验逻辑与行为一致性。 ## 项目结构 与材质删除相关的代码分布在以下模块: - 路由注册:定义DELETE /api/v1/texture/:id接口 - 处理器:解析参数、鉴权、调用服务层并返回响应 - 服务层:执行业务规则(权限校验、存在性校验)、调用仓储层 - 仓储层:执行数据库操作(软删除) - 数据模型:定义材质实体、收藏关系、下载日志等 ```mermaid graph TB Routes["路由注册
routes.go"] --> Handler["处理器
texture_handler.go"] Handler --> Service["服务层
texture_service.go"] Service --> Repo["仓储层
texture_repository.go"] Repo --> Model["数据模型
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["解析路径参数
获取材质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,配合日志便于排障。 - 关联清理:当前实现未清理收藏关系,如需可在业务层补充或扩展仓储层软删除逻辑。