|
|
||
|---|---|---|
| .idea | ||
| .trae/rules | ||
| .vscode | ||
| logs | ||
| monitoring | ||
| wangpan-common | ||
| wangpan-drive-service | ||
| wangpan-gateway | ||
| wangpan-tmdb-service | ||
| wangpan-user-service | ||
| API.md | ||
| pom.xml | ||
| PROJECT_REFERENCE.md | ||
| README.md | ||
| restart-services.ps1 | ||
| restart-services.sh | ||
WangPan 网盘系统
基于 Spring Cloud 微服务架构的个人网盘系统,支持文件管理、电影元数据刮削(TMDB)、用户认证等功能。
目录
项目简介
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. 克隆项目
git clone http://ldfun.asia:8418/djl1022/java.git
cd java
2. 编译项目
mvn clean install -DskipTests
3. 配置数据库与 MinIO
确保 MySQL 数据库 wangpan 已创建,MinIO 服务已启动。配置文件中的密码均使用 Jasypt 加密,无需手动修改。
4. 启动服务
必须通过以下命令启动每个服务(Jasypt 解密密钥必须传入):
# 启动用户服务(端口 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(加密后的密文)。
所有服务统一配置:
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 |
统一响应格式
{
"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) |
编码规范
- Controller 直接返回
Result<T>对象,不返回原始数据 - Repository 继承
ServiceImpl<Mapper, DO>,自动获得 CRUD 能力 - Mapper 继承
BaseMapper<DO>,简单 CRUD 自动生成 - 复杂 SQL 写在 Mapper XML 中,不写在 Java 代码中
- 数据库操作 使用
LambdaQueryWrapper/LambdaUpdateWrapper,不拼接 SQL 字符串 - 认证 使用
@RequireAuth和@RequireAdmin注解 - 当前用户 通过
request.getAttribute("currentUser")获取
MyBatis XML 映射规则
列别名一致性:XML 中 SELECT 的列别名必须与 Java 代码中 Map.get() 的 key 完全一致。
<!-- XML -->
SELECT title, COUNT(*) AS cnt FROM wp_drive_movie ...
// 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*:前缀(跨模块加载)
部署指南
生产环境环境变量
# Linux / Mac
export JASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024
# Windows PowerShell
$env:JASYPT_ENCRYPTOR_PASSWORD="wangpan-secret-key-2024"
Docker 部署
docker run -d \
-e JASYPT_ENCRYPTOR_PASSWORD=wangpan-secret-key-2024 \
-p 8081:8081 \
wangpan-user-service:latest
systemd 服务(Linux)
[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
启动顺序
- MySQL、MinIO(确保已启动)
wangpan-user-service(端口 8081)wangpan-drive-service(端口 8082)wangpan-tmdb-service(端口 8083)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 <token>。
Q4:如何修改数据库密码
- 修改原始密码后,使用 Jasypt 命令行工具重新加密
- 将加密后的密文替换
application.yml中的ENC(...)值 - 重启服务
Q5:网关路由不生效
原因:路由配置中 StripPrefix=0,且后端服务路径必须与网关路由完全匹配。
解决:检查 wangpan-gateway/application.yml 中的路由配置,确保转发目标正确。
项目参考文件
- PROJECT_REFERENCE.md — 项目全局参考文件(供 AI 辅助开发使用)
- api-doc.html — 在线 API 文档
许可证
内部项目,仅供学习与个人使用。