基于 Spring Boot 3 + PostgreSQL + Pulsar 的协同文件存储系统
本项目是一个面向多用户协作的网络文件存储系统,旨在模拟企业级应用的高并发与解耦设计。区别于传统的个人网盘,本项目采用了类似 Linux 文件系统的 Inode-Dentry 分离架构,重点解决了文件权限管理、多人实时协作、资源共享以及高并发下的数据一致性问题。
项目采用前后端分离架构,后端引入了 Apache Pulsar 消息队列处理耗时任务(如审计日志、物理删除),利用 Redis + Lua 脚本实现分布式锁以保障在线编辑的一致性,非常适合作为计算机专业深入理解分布式系统设计的实践项目。
- 注册与登录:基于 JWT + Redis 实现状态管理,支持 Token 自动过期与强制下线。
- 配额管理:每个用户拥有独立的存储空间配额(默认 1GB),上传与删除文件时原子更新配额。
基于 Inode (sys_file) 与 Dentry (sys_user_file) 分离的设计模式:
- 多文件并发上传:支持批量文件上传,后端采用线程池并行处理,物理落盘与元数据入库分离,确保高性能。
- 文件管理:
- 新建文件夹:支持多级目录结构。
- 文件移动:支持跨目录移动,内置“防环检测”算法防止目录死循环。
- 文件重命名:仅修改元数据,不影响物理文件,且不影响协作者视图。
- 递归删除:支持文件夹的级联删除。Owner 删除时触发 Pulsar 异步消息进行物理文件清理;协作者删除仅移除视图。
- 全局搜索:支持基于文件名的扁平化模糊搜索。
- 文件下载:支持流式下载,自动处理文件名编码。
- 细粒度权限控制 (RBAC):
- OWNER:拥有所有权,可删除、赋权。
- EDITOR:可编辑内容、重命名。
- VIEWER:仅可预览、下载。
- 技术实现:基于 AOP + 自定义注解 (
@RequireFileRole) 实现方法级鉴权。
- 共享管理:
- 发起共享:将文件“挂载”到目标用户的根目录下。
- 权限调整:Owner 可随时调整协作者权限或撤销共享。
- 成员查看:支持查看当前文件的所有协作者及其权限状态。
- 在线预览:支持预览纯文本文件、图片、PDF和DOCX文件。
- Read-Through 缓存策略:<1MB 的文本文件自动缓存至 Redis,提升读取速度。
- 在线编辑 (类飞书模式):支持编辑纯文本文件,包括.txt、.md、.java等。
- 分布式锁:使用 Redis + Lua 脚本 实现原子性的加锁 (
SETNX) 与解锁,防止多人同时修改同一文件。 - 心跳续期:前端定时发送心跳请求维持编辑锁。
- 同步落盘:保存时直接写入磁盘并清除缓存,确保数据强一致性。
- 分布式锁:使用 Redis + Lua 脚本 实现原子性的加锁 (
- 审计日志:全量记录用户的关键操作(上传、下载、修改、分享等)。
- 异步解耦:利用 Apache Pulsar 异步记录日志,不阻塞核心业务流程。
- 日志查询:
- 用户视角:查看个人的操作流水。
- 文件视角:查看某个文件的全生命周期变动记录(所有协作者的操作均可见)。
- 语言:Java 17+
- 框架:Spring Boot 3.x
- ORM:MyBatis Plus
- 数据库:PostgreSQL 16 (pgvector)
- 缓存 & 锁:Redis 6.2 (StringRedisTemplate, Lua Script)
- 消息队列:Apache Pulsar 4.0 (处理审计日志、物理删除)
- 工具库:Hutool, Lombok
- Docker + Docker Compose
系统核心包含 4 张表,体现了元数据分离的设计思想:
- sys_user: 用户基础信息、总空间、已用空间。
- sys_file (Inode): 物理文件表。记录物理路径、大小、类型。不包含文件名。
- sys_user_file (Dentry): 用户视图表。记录文件名、父目录 ID、权限角色 (Role)。这是实现多用户不同视图、文件共享的核心。
- sys_log: 审计日志表。记录操作人、操作类型、关联文件 ID、详情等。
确保本地已安装:
- JDK 21
- Maven 3.x
- Docker Desktop (推荐)
在项目根目录执行以下命令,启动 PostgreSQL, Redis, Pulsar:
Bash
docker-compose up -d
注意:首次启动 Pulsar 可能需要几分钟初始化。
连接 PostgreSQL (localhost:5432, user: postgres, pass: pg123456),执行 sql/init.sql (需根据数据库设计章节自行生成) 创建表结构。
检查 src/main/resources/application.yml:
YAML
spring:
datasource:
url: jdbc:postgresql://localhost:5432/netdisk_db
username: postgres
password: pg123456
data:
redis:
host: localhost
port: 6379
pulsar:
service-url: pulsar://localhost:6650
运行 NetdiskApplication.java。服务默认端口:8090。
详细接口定义见 Controller接口文档.md。
| 模块 | 接口路径前缀 | 描述 |
|---|---|---|
| 用户管理 | /api/user |
注册、登录、信息获取 |
| 文件管理 | /api/file |
上传、列表、搜索、新建文件夹、移动、重命名、删除 |
| 在线编辑 | /api/file |
/content(预览), /lock(加锁), /save(保存), /unlock(解锁) |
| 分享协作 | /api/share |
/add(分享), /revoke(撤销), /role(改权), /list(列表) |
| 系统日志 | /api/log |
/user(查个人), /file(查文件) |
- AOP 权限控制:使用
@RequireFileRole(UserRole.EDITOR)注解,将繁琐的权限校验逻辑从业务代码中剥离,实现了优雅的鉴权。 - 并发安全:在文件上传(配额扣减)和在线编辑(内容保存)场景下,分别使用了数据库行锁和 Redis 分布式锁,杜绝了并发导致的数据脏写问题。
- Lua 原子操作:在 Redis 锁的获取与释放过程中,使用 Lua 脚本保证了
Check-and-Set和Check-and-Del的原子性。 - 物理与逻辑分离:删除文件时,仅当引用计数归零(Owner 删除)时才真正删除物理文件,有效节省磁盘空间并支持秒级共享。