# 收藏管理 **本文引用的文件** - [server\src\modules\favorites\favorites.controller.ts](file://server/src/modules/favorites/favorites.controller.ts) - [server\src\modules\favorites\favorites.service.ts](file://server/src/modules/favorites/favorites.service.ts) - [server\src\middleware\auth.ts](file://server/src/middleware/auth.ts) - [server\prisma\schema.prisma](file://server/prisma/schema.prisma) - [my-uniapp-vue3\src\pages\favorites\index.vue](file://my-uniapp-vue3/src/pages/favorites/index.vue) - [docs\API.md](file://docs/API.md) ## 目录 1. [引言](#引言) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 引言 本指南围绕“收藏管理”功能,系统性阐述后端控制器与服务层、数据库模型、前端页面与交互、以及API接口规范。重点覆盖以下能力: - 收藏列表获取 - 添加收藏 - 取消收藏 - 收藏状态检查 并深入说明业务逻辑(用户身份验证、音频ID/书籍ID校验、重复收藏处理)、数据存储结构与查询优化策略,提供API接口文档与前端应用场景及用户交互设计,并给出常见问题与性能优化建议。 ## 项目结构 收藏功能由三层组成: - 前端页面:展示收藏列表、触发收藏/取消收藏、跳转播放页 - 后端控制器:接收请求、解析参数、调用服务层、返回统一响应 - 后端服务层:封装Prisma访问,执行查询/插入/删除/存在性检查 - 数据库模型:Favorite、Book、User三者关联,唯一索引避免重复收藏 ```mermaid graph TB FE["前端页面
收藏列表页"] --> API["后端控制器
favorites.controller.ts"] API --> SVC["服务层
favorites.service.ts"] SVC --> PRISMA["Prisma 客户端"] PRISMA --> DB["数据库
schema.prisma 中的 Favorite/Book/User"] ``` 图表来源 - [server\src\modules\favorites\favorites.controller.ts:1-76](file://server/src/modules/favorites/favorites.controller.ts#L1-L76) - [server\src\modules\favorites\favorites.service.ts:1-104](file://server/src/modules/favorites/favorites.service.ts#L1-L104) - [server\prisma\schema.prisma:94-105](file://server/prisma/schema.prisma#L94-L105) 章节来源 - [server\src\modules\favorites\favorites.controller.ts:1-76](file://server/src/modules/favorites/favorites.controller.ts#L1-L76) - [server\src\modules\favorites\favorites.service.ts:1-104](file://server/src/modules/favorites/favorites.service.ts#L1-L104) - [server\prisma\schema.prisma:94-105](file://server/prisma/schema.prisma#L94-L105) ## 核心组件 - 控制器层:定义路由、参数解析、鉴权中间件、统一响应格式 - 服务层:封装Prisma查询,处理重复收藏、排序与关联查询 - 鉴权中间件:可选认证,开发环境默认测试用户 - 数据模型:Favorite唯一约束、索引优化、与Book/User关联 章节来源 - [server\src\modules\favorites\favorites.controller.ts:1-76](file://server/src/modules/favorites/favorites.controller.ts#L1-L76) - [server\src\modules\favorites\favorites.service.ts:1-104](file://server/src/modules/favorites/favorites.service.ts#L1-L104) - [server\src\middleware\auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80) - [server\prisma\schema.prisma:94-105](file://server/prisma/schema.prisma#L94-L105) ## 架构总览 收藏功能遵循“控制器-服务-数据模型”的分层架构,前端通过HTTP请求与后端交互,后端通过Prisma访问MySQL数据库。 ```mermaid sequenceDiagram participant U as "用户" participant FE as "前端页面" participant CTRL as "控制器
favorites.controller.ts" participant SVC as "服务层
favorites.service.ts" participant DB as "数据库
Prisma/MySQL" U->>FE : 打开收藏页面 FE->>CTRL : GET /favorites CTRL->>SVC : getFavorites(userId) SVC->>DB : 查询收藏记录(含book关联) DB-->>SVC : 收藏列表 SVC-->>CTRL : 返回结果 CTRL-->>FE : 统一响应 U->>FE : 点击添加收藏 FE->>CTRL : POST /favorites {audioId} CTRL->>SVC : addFavorite(userId, bookId) SVC->>DB : 检查重复(唯一索引) alt 已存在 DB-->>SVC : 存在 SVC-->>CTRL : 返回现有收藏 else 不存在 DB-->>SVC : 插入新收藏 SVC-->>CTRL : 返回新建收藏 end CTRL-->>FE : 统一响应 U->>FE : 点击取消收藏 FE->>CTRL : DELETE /favorites/ : audioId CTRL->>SVC : removeFavorite(userId, bookId) SVC->>DB : 删除收藏 DB-->>SVC : 成功 SVC-->>CTRL : 返回 CTRL-->>FE : 统一响应 U->>FE : 检查收藏状态 FE->>CTRL : GET /favorites/check/ : audioId CTRL->>SVC : isFavorited(userId, bookId) SVC->>DB : 查找唯一键 DB-->>SVC : 存在/不存在 SVC-->>CTRL : 返回布尔值 CTRL-->>FE : 统一响应 ``` 图表来源 - [server\src\modules\favorites\favorites.controller.ts:13-73](file://server/src/modules/favorites/favorites.controller.ts#L13-L73) - [server\src\modules\favorites\favorites.service.ts:8-103](file://server/src/modules/favorites/favorites.service.ts#L8-L103) - [server\prisma\schema.prisma:94-105](file://server/prisma/schema.prisma#L94-L105) ## 详细组件分析 ### 控制器层(favorites.controller.ts) - 路由定义 - GET /favorites:获取当前用户的收藏列表 - POST /favorites:添加收藏(请求体包含audioId) - DELETE /favorites/:audioId:取消收藏 - GET /favorites/check/:audioId:检查是否已收藏 - 鉴权策略 - 使用可选认证中间件,支持无Token时使用测试用户 - 开发环境可通过环境变量控制是否强制认证 - 统一响应 - 固定返回结构:code、message、data - 错误通过错误处理器抛出,由全局中间件捕获 章节来源 - [server\src\modules\favorites\favorites.controller.ts:13-73](file://server/src/modules/favorites/favorites.controller.ts#L13-L73) - [server\src\middleware\auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80) ### 服务层(favorites.service.ts) - 数据访问 - getFavorites:按用户ID查询收藏,包含book关联字段,按创建时间倒序 - addFavorite:先查重(唯一索引),存在则返回现有;否则创建新收藏并返回带book的完整信息 - removeFavorite:按唯一键删除收藏 - isFavorited:按唯一键判断是否存在 - 关联查询 - 通过Prisma include book,减少二次查询 - 性能要点 - 唯一键约束避免重复收藏 - 查询使用索引字段(userId、bookId) 章节来源 - [server\src\modules\favorites\favorites.service.ts:8-103](file://server/src/modules/favorites/favorites.service.ts#L8-L103) - [server\prisma\schema.prisma:94-105](file://server/prisma/schema.prisma#L94-L105) ### 数据模型(schema.prisma) - Favorite - 唯一键:userId + bookId - 索引:userId、bookId - 关系:属于User、属于Book(级联删除) - Book - 收藏反向关系:favorites - User - 收藏反向关系:favorites ```mermaid erDiagram USER ||--o{ FAVORITE : "拥有" BOOK ||--o{ FAVORITE : "被收藏" FAVORITE { int id PK int userId int bookId datetime createdAt } USER { int id PK } BOOK { int id PK } ``` 图表来源 - [server\prisma\schema.prisma:94-105](file://server/prisma/schema.prisma#L94-L105) 章节来源 - [server\prisma\schema.prisma:94-105](file://server/prisma/schema.prisma#L94-L105) ### 前端应用(favorites/index.vue) - 页面职责 - 加载收藏列表、空状态提示、点击播放、点击取消收藏 - 交互流程 - 打开页面即拉取收藏列表 - 点击条目跳转播放页 - 点击右侧爱心图标触发取消收藏,成功后从本地列表剔除 - 类型定义 - FavoriteItem:包含收藏项ID、音频ID、创建时间、音频信息等 章节来源 - [my-uniapp-vue3\src\pages\favorites\index.vue:47-112](file://my-uniapp-vue3/src/pages/favorites/index.vue#L47-L112) ## 依赖关系分析 - 控制器依赖服务层 - 服务层依赖Prisma客户端访问数据库 - 鉴权中间件贯穿控制器层 - 前端依赖统一的HTTP请求工具与后端API ```mermaid graph LR AUTH["鉴权中间件
auth.ts"] --> CTRL["控制器
favorites.controller.ts"] CTRL --> SVC["服务层
favorites.service.ts"] SVC --> PRISMA["Prisma 客户端"] PRISMA --> DB["MySQL 数据库"] FE["前端页面
favorites/index.vue"] --> CTRL ``` 图表来源 - [server\src\middleware\auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80) - [server\src\modules\favorites\favorites.controller.ts:1-76](file://server/src/modules/favorites/favorites.controller.ts#L1-L76) - [server\src\modules\favorites\favorites.service.ts:1-104](file://server/src/modules/favorites/favorites.service.ts#L1-L104) 章节来源 - [server\src\middleware\auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80) - [server\src\modules\favorites\favorites.controller.ts:1-76](file://server/src/modules/favorites/favorites.controller.ts#L1-L76) - [server\src\modules\favorites\favorites.service.ts:1-104](file://server/src/modules\favorites/favorites.service.ts#L1-L104) ## 性能考量 - 查询优化 - 使用唯一索引(userId, bookId)保证重复收藏检查高效 - 对userId、bookId建立索引,提升查询与删除效率 - 关联查询 - 通过include book一次性返回所需字段,避免N+1查询 - 排序与分页 - 按创建时间倒序,适合“最近收藏”展示 - 如需分页,可在服务层增加skip/take参数 - 缓存策略 - 对热门用户收藏可考虑Redis缓存,降低数据库压力 - 并发控制 - 唯一键约束天然防止并发重复插入 - 日志与监控 - 记录慢查询与异常,结合数据库慢日志定位瓶颈 ## 故障排查指南 - 常见问题 - 未登录或Token无效:确认鉴权中间件配置与Token格式 - 收藏重复:唯一键约束会阻止重复,检查是否正确处理已存在情况 - 取消收藏失败:确认传入的audioId是否正确、用户是否匹配 - 收藏列表为空:确认用户是否有收藏记录、include book是否正常 - 排查步骤 - 检查控制器参数解析与类型转换 - 在服务层打印SQL与参数,核对userId与bookId - 核对Prisma schema中的唯一键与索引 - 前端确认请求URL与请求头(Authorization) - 错误处理 - 控制器层统一抛出错误,响应格式固定 - 前端根据code与message进行提示 章节来源 - [server\src\modules\favorites\favorites.controller.ts:33-35](file://server/src/modules/favorites/favorites.controller.ts#L33-L35) - [server\src\modules\favorites\favorites.service.ts:37-49](file://server/src/modules\favorites/favorites.service.ts#L37-L49) - [server\src\middleware\auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80) ## 结论 收藏管理功能采用清晰的分层架构与完善的数据库约束,实现了稳定的收藏列表、添加、取消与状态检查能力。通过唯一键与索引优化、关联查询与统一响应,兼顾了易用性与性能。前端页面简洁直观,配合后端API即可快速落地。 ## 附录 ### API接口文档(收藏相关) - 获取收藏列表 - 方法:GET - URL:/favorites - 请求头:Authorization: Bearer (可选) - 响应:code、message、data(收藏列表) - 添加收藏 - 方法:POST - URL:/favorites - 请求头:Authorization: Bearer (可选) - 请求体:{ audioId: number } - 响应:code、message、data(收藏项) - 取消收藏 - 方法:DELETE - URL:/favorites/:audioId - 请求头:Authorization: Bearer (可选) - 响应:code、message - 检查是否已收藏 - 方法:GET - URL:/favorites/check/:audioId - 请求头:Authorization: Bearer (可选) - 响应:code、message、data: { isFavorited: boolean } 章节来源 - [server\src\modules\favorites\favorites.controller.ts:13-73](file://server/src/modules/favorites/favorites.controller.ts#L13-L73) - [docs\API.md:257-276](file://docs/API.md#L257-L276) ### 数据模型与查询流程图 ```mermaid flowchart TD Start(["进入收藏服务"]) --> Parse["解析用户ID与音频ID"] Parse --> CheckDup{"是否已收藏?"} CheckDup --> |是| ReturnExist["返回现有收藏"] CheckDup --> |否| Insert["创建新收藏"] Insert --> ReturnNew["返回新建收藏"] ReturnExist --> End(["结束"]) ReturnNew --> End ``` 图表来源 - [server\src\modules\favorites\favorites.service.ts:34-69](file://server/src/modules/favorites/favorites.service.ts#L34-L69)