diff --git a/README.md b/README.md new file mode 100644 index 0000000..c910d11 --- /dev/null +++ b/README.md @@ -0,0 +1,482 @@ +# WangPan 网盘系统 + +> 基于 Spring Cloud 微服务架构的个人网盘系统,支持文件管理、电影元数据刮削(TMDB)、用户认证等功能。 + +--- + +## 目录 + +- [项目简介](#项目简介) +- [技术栈](#技术栈) +- [模块架构](#模块架构) +- [快速开始](#快速开始) +- [配置说明](#配置说明) +- [API 接口文档](#api-接口文档) +- [数据库设计](#数据库设计) +- [项目规范](#项目规范) +- [部署指南](#部署指南) +- [常见问题](#常见问题) + +--- + +## 项目简介 + +WangPan 是一个功能完整的个人网盘系统,采用微服务架构设计,主要功能包括: + +- **用户认证**:注册、登录、Token 管理、登录日志 +- **网盘管理**:创建网盘、文件夹管理、电影文件上传/管理 +- **TMDB 刮削**:自动从 TMDB 获取电影元数据(标题、评分、海报、简介等) +- **Icon 管理**:自定义图标上传与管理 +- **API 网关**:统一入口,路由转发,认证拦截 + +--- + +## 技术栈 + +| 技术 | 版本 | 用途 | +|------|------|------| +| Java | 17 | 开发语言 | +| Spring Boot | 3.2.5 | 应用框架 | +| Spring Cloud Gateway | 2023.0.1 | API 网关 | +| MyBatis-Plus | 3.5.7 | ORM 框架 | +| MySQL | 8.0.33 | 关系型数据库 | +| MinIO | 8.5.7 | 对象存储(文件/图片) | +| Jasypt | 3.0.5 | 配置文件加密 | +| Maven | 3.x | 构建工具 | + +--- + +## 模块架构 + +``` +wangpan/ +├── wangpan-common/ # 公共模块(DO/Mapper/Repository/Entity/Util/Interceptor) +├── wangpan-user-service/ # 用户认证服务(端口 8081) +├── wangpan-drive-service/ # 网盘管理服务(端口 8082) +├── wangpan-tmdb-service/ # TMDB 刮削服务(端口 8083) +└── wangpan-gateway/ # API 网关(端口 8888) +``` + +### 服务端口与职责 + +| 服务 | 端口 | 职责 | +|------|------|------| +| `wangpan-user-service` | 8081 | 用户注册、登录、Token 签发与验证、登录日志 | +| `wangpan-drive-service` | 8082 | 网盘 CRUD、文件夹管理、电影管理、Icon 管理、重复检测 | +| `wangpan-tmdb-service` | 8083 | TMDB API 调用、电影元数据刮削、刮削缓存、定时扫描 | +| `wangpan-gateway` | 8888 | 统一路由入口、CORS 跨域、认证拦截、API 文档页面 | + +### 分层架构 + +``` +Controller → 接收请求、参数校验、调用 Service、返回 Result + ↓ +Service → 业务逻辑处理、事务管理 + ↓ +Repository → 数据访问封装、Entity ↔ DO 转换、LambdaQueryWrapper 查询 + ↓ +Mapper → MyBatis-Plus BaseMapper 接口 + XML 复杂 SQL + ↓ +DO → 数据库表映射(@TableName 注解) +``` + +--- + +## 快速开始 + +### 环境要求 + +- JDK 17+ +- Maven 3.6+ +- MySQL 8.0+ +- MinIO Server + +### 1. 克隆项目 + +```bash +git clone http://ldfun.asia:8418/djl1022/java.git +cd java +``` + +### 2. 编译项目 + +```bash +mvn clean install -DskipTests +``` + +### 3. 配置数据库与 MinIO + +确保 MySQL 数据库 `wangpan` 已创建,MinIO 服务已启动。配置文件中的密码均使用 Jasypt 加密,无需手动修改。 + +### 4. 启动服务 + +**必须通过以下命令启动每个服务**(Jasypt 解密密钥必须传入): + +```bash +# 启动用户服务(端口 8081) +java -DJASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 -jar wangpan-user-service/target/wangpan-user-service-1.0-SNAPSHOT.jar + +# 启动网盘服务(端口 8082) +java -DJASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 -jar wangpan-drive-service/target/wangpan-drive-service-1.0-SNAPSHOT.jar + +# 启动 TMDB 服务(端口 8083) +java -DJASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 -jar wangpan-tmdb-service/target/wangpan-tmdb-service-1.0-SNAPSHOT.jar + +# 启动网关(端口 8888) +java -DJASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 -jar wangpan-gateway/target/wangpan-gateway-1.0-SNAPSHOT.jar +``` + +> **注意**:`-DJASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024` 是解密配置文件中加密密码的密钥,**必须传入**,否则服务启动会报错。 + +### 5. 访问系统 + +- **API 网关**:http://localhost:8888 +- **API 文档页面**:http://localhost:8888/api-doc.html +- **各服务 Swagger**:http://localhost:8081/swagger-ui.html 等 + +--- + +## 配置说明 + +### Jasypt 配置加密 + +所有敏感信息(数据库密码、MinIO 密钥、TMDB API Key)均使用 Jasypt 加密存储,格式为 `ENC(加密后的密文)`。 + +**所有服务统一配置**: + +```yaml +jasypt: + encryptor: + password: ${JASYPT_ENCRYPTOR_PASSWORD} # 必须通过环境变量或 -D 参数传入 + algorithm: PBEWITHHMACSHA512ANDAES_256 # 统一使用强加密算法 + key-obtention-iterations: 1000 + pool-size: 1 + salt-generator-classname: org.jasypt.salt.RandomSaltGenerator + iv-generator-classname: org.jasypt.iv.RandomIvGenerator + string-output-type: base64 +``` + +**加密密钥**:`wangpan-secret-key-2024` + +### 数据库连接 + +- **地址**:`118.178.238.159:33306` +- **数据库名**:`wangpan` +- **连接参数**:`useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true` + +### MinIO 对象存储 + +- **地址**:`118.178.238.159:39000` +- **存储桶**:`wangpan`(网盘文件)、`tmdb`(TMDB 缓存数据) + +### 网关路由 + +| 路由路径 | 转发目标 | +|---------|---------| +| `/api/login`, `/api/register` | `http://localhost:8081` | +| `/api/token/**`, `/api/login-logs/**` | `http://localhost:8081` | +| `/api/users/**` | `http://localhost:8081` | +| `/api/drive/**` | `http://localhost:8082` | +| `/api/icon/**` | `http://localhost:8082` | +| `/api/movies/**` | `http://localhost:8083` | +| `/api/tmdb/**`, `/api/tmdb-scraper/**` | `http://localhost:8083` | + +所有路由 `StripPrefix=0`(不裁剪路径前缀)。 + +--- + +## API 接口文档 + +完整 API 文档请访问:**http://localhost:8888/api-doc.html** + +### 用户服务(端口 8081) + +| 方法 | 路径 | 说明 | 认证 | +|------|------|------|------| +| POST | `/api/login` | 用户登录 | 否 | +| POST | `/api/register` | 用户注册 | 否 | +| GET | `/api/token/validate` | 验证 Token | 否 | +| GET | `/api/login-logs` | 查询登录日志 | 需Token | +| GET | `/api/users` | 查询用户列表 | 需Token | +| POST | `/api/users` | 创建用户 | 需Token | +| PUT | `/api/users/{userId}` | 更新用户 | 需Token | +| DELETE | `/api/users/{userId}` | 删除用户 | 需Token | + +### 网盘服务(端口 8082) + +| 方法 | 路径 | 说明 | 认证 | +|------|------|------|------| +| POST | `/api/drive` | 创建网盘 | 需Token | +| GET | `/api/drive` | 查询网盘列表 | 需Token | +| GET | `/api/drive/{id}` | 查询网盘详情 | 需Token | +| PUT | `/api/drive/{id}` | 更新网盘 | 需Token | +| DELETE | `/api/drive/{id}` | 删除网盘 | 需Token | +| POST | `/api/drive/{driveId}/folders` | 创建文件夹 | 需Token | +| GET | `/api/drive/{driveId}/folders` | 查询文件夹列表 | 需Token | +| GET | `/api/drive/{driveId}/folders/{folderId}` | 查询文件夹详情 | 需Token | +| PUT | `/api/drive/{driveId}/folders/{folderId}` | 更新文件夹 | 需Token | +| DELETE | `/api/drive/{driveId}/folders/{folderId}` | 删除文件夹 | 需Token | +| POST | `/api/drive/{driveId}/movies` | 添加电影 | 需Token | +| GET | `/api/drive/{driveId}/folders/{folderId}/movies` | 查询电影列表 | 需Token | +| GET | `/api/drive/{driveId}/movies/{movieId}` | 查询电影详情 | 需Token | +| PUT | `/api/drive/{driveId}/movies/{movieId}` | 更新电影 | 需Token | +| DELETE | `/api/drive/{driveId}/movies/{movieId}` | 删除电影 | 需Token | +| GET | `/api/drive/movies/duplicates` | 检查重复电影 | 需Token | +| POST | `/api/icon` | 创建图标 | 需Token | +| GET | `/api/icon` | 查询图标列表 | 需Token | +| GET | `/api/icon/{id}` | 查询图标详情 | 需Token | +| PUT | `/api/icon/{id}` | 更新图标 | 需Token | +| DELETE | `/api/icon/{id}` | 删除图标 | 需Token | +| POST | `/api/icon/{id}/logo` | 上传图标 Logo | 需Token | + +### TMDB 服务(端口 8083) + +| 方法 | 路径 | 说明 | 认证 | +|------|------|------|------| +| GET | `/api/movies` | 查询电影列表 | 需Token | +| GET | `/api/movies/recommend` | 推荐电影 | 需Token | +| GET | `/api/movies/{id}` | 查询电影详情 | 需Token | +| POST | `/api/movies` | 创建电影 | 需Token | +| PUT | `/api/movies/{id}` | 更新电影 | 需Token | +| DELETE | `/api/movies/{id}` | 删除电影 | 需Token | +| POST | `/api/movies/batch-delete` | 批量删除电影 | 需Token | +| GET | `/api/movies/stats` | 电影统计 | 需Token | +| GET | `/api/tmdb/key` | 查询 TMDB API Key | 需Token | +| POST | `/api/tmdb/key` | 设置 TMDB API Key | 需Token | +| POST | `/api/tmdb-scraper/scrape` | 单部电影刮削 | 需Token | +| POST | `/api/tmdb-scraper/batch-scrape` | 批量刮削 | 需Token | +| GET | `/api/tmdb-scraper/caches` | 查询刮削缓存 | 需Token | +| GET | `/api/tmdb-scraper/stats` | 刮削统计 | 需Token | +| POST | `/api/tmdb-scraper/trigger` | 手动触发定时任务 | 需Token | +| GET | `/api/tmdb-scraper/scraper-logs` | 查询刮削日志 | 需Token | +| DELETE | `/api/tmdb-scraper/cache/{movieId}` | 删除缓存 | 需Token | + +### 统一响应格式 + +```json +{ + "code": 200, + "message": "操作成功", + "data": {} +} +``` + +| 状态码 | 含义 | +|--------|------| +| 200 | 操作成功 | +| 400 | 参数错误 | +| 401 | 未登录 / Token 过期 | +| 403 | 权限不足 | +| 404 | 资源不存在 | +| 429 | 请求过于频繁 | +| 500 | 服务器内部错误 | + +--- + +## 数据库设计 + +### 核心表结构 + +| 表名 | 所属模块 | 说明 | +|------|---------|------| +| `wp_user` | user-service | 用户表 | +| `wp_drive` | drive-service | 网盘表 | +| `wp_drive_folder` | drive-service | 文件夹表 | +| `wp_drive_movie` | drive-service | 电影表(唯一电影数据表) | +| `wp_tmdb_cache` | tmdb-service | TMDB 刮削缓存表 | +| `wp_tmdb_scraper_log` | tmdb-service | 刮削日志表 | +| `wp_tmdb_config` | tmdb-service | TMDB API 配置表 | +| `wp_login_log` | user-service | 登录日志表 | +| `wp_icon` | drive-service | 图标表 | + +### 表命名规范 + +- 所有表以 `wp_` 前缀开头 +- 表名使用小写 + 下划线分隔 +- 主键统一为 `id`(BIGINT AUTO_INCREMENT) +- 状态字段使用字符串枚举值(如 `active`, `deleted`) +- 索引命名:`idx_字段名` + +### 重要约定 + +> **`wp_drive_movie` 是项目中唯一的电影数据表**,所有模块(drive-service、tmdb-service)都操作同一张表。不存在 `wp_movie` 表(已废弃)。 + +--- + +## 项目规范 + +### 命名规范 + +#### 包结构 + +``` +com.wangpan +├── common/ # 公共模块 +│ ├── annotation/ # 自定义注解(@RequireAuth, @RequireAdmin) +│ ├── config/ # 配置类 +│ ├── dal/ # 数据访问层 +│ │ ├── dataobject/ # DO 数据对象 +│ │ ├── mapper/ # MyBatis Mapper 接口 +│ │ └── repository/ # Repository 封装 +│ ├── entity/ # 业务实体 +│ ├── interceptor/ # 拦截器 +│ ├── listener/ # 定时任务 +│ └── util/ # 工具类 +├── controller/ # 控制器(各子模块独立) +├── service/ # 业务服务(各子模块独立) +└── Application.java # 启动类(各子模块独立) +``` + +#### 类命名 + +| 类型 | 规则 | 示例 | +|------|------|------| +| DO | `{实体名}DO` | `DriveMovieDO`, `UserDO` | +| Mapper | `{实体名}Mapper` | `DriveMovieMapper`, `UserMapper` | +| Repository | `{实体名}Repository` | `DriveMovieRepository` | +| Entity | `{实体名}` | `DriveMovie`, `User` | +| Controller | `{模块名}Controller` | `DriveController`, `AuthController` | +| Service | `{模块名}Service` | `DriveService`, `TmdbScraperService` | +| 工具类 | `{功能}Util` | `TokenUtil`, `MinioUtil`, `EncryptUtil` | +| 配置类 | `{功能}Config` | `WebMvcConfig`, `MyBatisPlusConfig` | +| 定时任务 | `{功能}Scheduler` | `TmdbScheduler`, `IconCleanupScheduler` | + +#### 方法命名 + +| 操作 | 规则 | 示例 | +|------|------|------| +| 查询单个 | `findBy{条件}` | `findById`, `findByMovieId` | +| 查询列表 | `queryBy{条件}` | `queryByUserId`, `queryByDriveAndFolder` | +| 统计 | `countBy{条件}` | `countByDrive`, `countByUser` | +| 插入 | `insert` | `insert(DriveMovie movie)` | +| 更新 | `update` / `update{字段}` | `update`, `updateScrapeInfo` | +| 逻辑删除 | `logicalDelete` | `logicalDelete(Long id, Long userId)` | +| 物理删除 | `delete` | `delete(Long id, Long userId)` | + +### 编码规范 + +1. **Controller** 直接返回 `Result` 对象,不返回原始数据 +2. **Repository** 继承 `ServiceImpl`,自动获得 CRUD 能力 +3. **Mapper** 继承 `BaseMapper`,简单 CRUD 自动生成 +4. **复杂 SQL** 写在 Mapper XML 中,不写在 Java 代码中 +5. **数据库操作** 使用 `LambdaQueryWrapper` / `LambdaUpdateWrapper`,不拼接 SQL 字符串 +6. **认证** 使用 `@RequireAuth` 和 `@RequireAdmin` 注解 +7. **当前用户** 通过 `request.getAttribute("currentUser")` 获取 + +### MyBatis XML 映射规则 + +**列别名一致性**:XML 中 `SELECT` 的列别名必须与 Java 代码中 `Map.get()` 的 key 完全一致。 + +```xml + +SELECT title, COUNT(*) AS cnt FROM wp_drive_movie ... +``` + +```java +// Java 中必须使用相同的 key +g.get("cnt") // ✅ 正确 +g.get("count") // ❌ 错误,别名是 cnt 不是 count +``` + +**数值安全转换**:`resultType="java.util.Map"` 返回的数值,使用 `((Number) g.get("cnt")).intValue()` 安全转换。 + +### 配置文件规范 + +- 所有敏感信息使用 Jasypt `ENC(...)` 加密 +- 所有服务 Jasypt 加密算法统一为 `PBEWITHHMACSHA512ANDAES_256` +- 日志级别生产环境设为 `INFO` +- 不启用 MyBatis-Plus SQL 日志输出到控制台 +- Mapper XML 路径使用 `classpath*:` 前缀(跨模块加载) + +--- + +## 部署指南 + +### 生产环境环境变量 + +```bash +# Linux / Mac +export JASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 + +# Windows PowerShell +$env:JASYPT_ENCRYPTOR_PASSWORD="wangpan-secret-key-2024" +``` + +### Docker 部署 + +```bash +docker run -d \ + -e JASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 \ + -p 8081:8081 \ + wangpan-user-service:latest +``` + +### systemd 服务(Linux) + +```ini +[Unit] +Description=WangPan User Service + +[Service] +Environment=JASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 +ExecStart=/usr/bin/java -jar /opt/wangpan/wangpan-user-service.jar +Restart=on-failure + +[Install] +WantedBy=multi-user.target +``` + +### 启动顺序 + +1. MySQL、MinIO(确保已启动) +2. `wangpan-user-service`(端口 8081) +3. `wangpan-drive-service`(端口 8082) +4. `wangpan-tmdb-service`(端口 8083) +5. `wangpan-gateway`(端口 8888) + +--- + +## 常见问题 + +### Q1:启动报错 `Failed to bind properties under 'spring.datasource.password'` + +**原因**:Jasypt 解密密钥未正确传入。 + +**解决**:使用 `-DJASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024` 参数启动,不要用 `$env:xxx` 方式设置环境变量(Windows 下 `Start-Process` 子进程不继承)。 + +### Q2:TMDB 刮削返回"没有需要刮削的电影" + +**原因**:`wp_drive_movie` 表中没有电影数据,或现有电影的 `scrapeType` 字段为 `none`。 + +**解决**:先通过网盘服务上传电影文件,或通过 `POST /api/movies` 创建电影记录,确保 `scrapeType` 不为 `none`。 + +### Q3:API 返回 401 未授权 + +**原因**:Token 过期或未登录。 + +**解决**:先调用 `POST /api/login` 获取 Token,在请求头中携带 `Authorization: Bearer `。 + +### Q4:如何修改数据库密码 + +1. 修改原始密码后,使用 Jasypt 命令行工具重新加密 +2. 将加密后的密文替换 `application.yml` 中的 `ENC(...)` 值 +3. 重启服务 + +### Q5:网关路由不生效 + +**原因**:路由配置中 `StripPrefix=0`,且后端服务路径必须与网关路由完全匹配。 + +**解决**:检查 `wangpan-gateway/application.yml` 中的路由配置,确保转发目标正确。 + +--- + +## 项目参考文件 + +- [PROJECT_REFERENCE.md](./PROJECT_REFERENCE.md) — 项目全局参考文件(供 AI 辅助开发使用) +- [api-doc.html](./wangpan-gateway/src/main/resources/META-INF/resources/api-doc.html) — 在线 API 文档 + +--- + +## 许可证 + +内部项目,仅供学习与个人使用。 \ No newline at end of file