本文件为 Claude Code (claude.ai/code) 在此代码库中工作时提供指导。
Snapshot 是一个临时文件分享平台,提供文件和文本内容的安全临时分享服务。
# 进入后端目录
cd backend
# 编译打包
mvn clean package -DskipTests
# 运行应用
java -jar target/snapshot-backend-1.0.0.jar
# 或使用部署脚本(Windows)
deploy.bat
数据库初始化:
# 首次运行前,在MySQL中执行
mysql -uroot -p < backend/src/main/resources/sql/create.sql
# 进入前端目录
cd frontend
# 安装依赖(首次)
npm install
# 开发模式运行
npm run serve
# 生产构建
npm run build
# 代码检查
npm run lint
# 或使用部署脚本(Windows)
deploy.bat
# 访问 http://localhost:7626 查看页面
snapshot/
├── backend/ # Spring Boot后端
│ ├── src/main/java/com/snapshot/
│ │ ├── entity/ # JPA实体类
│ │ ├── repository/ # 数据访问层
│ │ ├── service/ # 业务逻辑层
│ │ ├── controller/ # REST API控制器
│ │ ├── dto/ # 数据传输对象
│ │ ├── config/ # 配置类(CORS、定时任务)
│ │ ├── util/ # 工具类(ID生成、密码哈希)
│ │ └── exception/ # 全局异常处理
│ ├── src/main/resources/
│ │ ├── sql/create.sql # 数据库初始化脚本
│ │ └── application.properties
│ └── pom.xml
│
├── frontend/ # Vue 3前端
│ ├── src/
│ │ ├── api/ # API接口封装(Axios)
│ │ ├── stores/ # Pinia状态管理
│ │ ├── router/ # 路由配置
│ │ ├── views/ # 页面组件(Home.vue, Share.vue)
│ │ ├── components/ # 可复用组件
│ │ ├── styles/ # 全局样式
│ │ ├── config.js # 前端配置(API地址、限制)
│ │ └── main.js
│ └── package.json
│
└── api/
└── API_DOCUMENT.md # RESTful API接口文档
Controller层: 处理HTTP请求,调用Service层
UploadController: 文件/文本上传、删除ShareController: 内容访问、下载、密码验证Service层: 核心业务逻辑
UploadRecordService: 上传记录管理、字典树构建、过期清理FileStorageService: 文件存储管理(文件读写、删除)Repository层: JPA数据访问
UploadRecordRepository: 上传记录CRUDFileEntryRepository: 文件元数据管理TextContentRepository: 文本内容管理TrieNodeRepository: 字典树节点管理(前缀查询)Entity层: 数据库实体映射
UploadRecord: 上传记录(ID、过期时间、下载次数、密码哈希)FileEntry: 文件元数据(文件名、大小、MIME类型、存储路径)TextContent: 文本内容TrieNode: 字典树节点(nodeKey、parentId、depth、uploadId)工具类:
IdGenerator: 随机ID生成(可配置长度和字符集,默认8位)PasswordUtil: 密码SHA-256哈希页面路由 (Vue Router):
/: 首页 - 文件上传和文本分享/s/:id: 分享页面 - 查看和下载内容/*: 404页面状态管理 (Pinia):
uploadStore: 管理上传状态(文件列表、进度、配置)API通信:
config.jsUI特点:
问题: 用户输入ID前几位时,如何快速定位到完整内容?
解决方案: 使用字典树(Trie)数据结构
实现原理:
a1b2c3d4"),在后端构建字典树a → 1 → b → 2 → c → 3 → d → 4关键代码:
UploadRecordService.buildTrie(): 构建字典树(创建上传记录时自动调用)UploadRecordService.resolveIdByPrefix(): 前缀解析TrieNodeRepository.findByPrefix(): 数据库查询前缀匹配节点表结构 (trie_nodes):
node_id (主键) | node_key | parent_id | depth | upload_id
初始化上传: POST /api/upload/init
上传文件: POST /api/upload/{uploadId}/files
./uploads 目录更新文本: PUT /api/upload/{uploadId}/text
完成上传: POST /api/upload/{uploadId}/complete
http://localhost:7626/s/{id}内容访问: GET /api/content/{id}
密码验证: POST /api/content/{id}/verify-password
下载文件: GET /api/download/file/{fileId}
打包下载: GET /api/download/bundle/{uploadId}
配置: app.cleanup.cron=0 0 */2 * * ?(每2小时执行一次)
逻辑: UploadRecordService.cleanupExpiredRecords()
expirationTime < now)FileStorageService)application.properties)关键配置项:
# 服务端口
server.port=7626
# 文件上传限制
spring.servlet.multipart.max-file-size=50MB
spring.servlet.multipart.max-request-size=500MB
# 数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/snapshot
spring.datasource.username=root
spring.datasource.password=<YOUR_MYSQL_PASSWORD>
# 文件存储路径
app.file.upload-dir=./uploads
# ID生成器
app.id.length=8
app.id.charset=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
# 过期清理任务(cron表达式)
app.cleanup.cron=0 0 */2 * * ?
config.js){
baseURL: 'http://localhost:7626',
uploadLimit: 50 * 1024 * 1024, // 50MB
maxFiles: 10,
expirationOptions: [1, 2, 3, 6, 12, 24]
}
upload_records: 上传记录主表
id (主键): 8位随机字符串expiration_time: 过期时间max_download_count: 最大下载次数(-1表示无限制)current_download_count: 当前下载次数password_hash: 密码SHA-256哈希(可选)file_entries: 文件元数据
file_id: 文件唯一IDupload_id: 关联上传记录file_name, file_size, mime_typestorage_path: 服务器文件路径upload_status: 上传状态(uploading/completed/failed)upload_progress: 上传进度(0-100)text_contents: 文本内容
upload_id: 关联上传记录text_content, text_typetrie_nodes: 字典树节点(用于前缀查询)
node_key: 字符parent_id: 父节点IDdepth: 深度(从1开始)upload_id: 完整ID(仅叶子节点存储)初始化脚本: backend/src/main/resources/sql/create.sql
./uploads)./uploads 目录(项目根目录下)详细的RESTful API接口文档请参考: api/API_DOCUMENT.md
主要接口:
POST /api/upload/init, POST /api/upload/{id}/files, PUT /api/upload/{id}/textGET /api/content/{id}, POST /api/content/{id}/verify-passwordGET /api/download/file/{fileId}, GET /api/download/bundle/{id}GET /api/query/lookup?prefix=xxxbackend/src/main/java/com/snapshot/controller/ 创建或修改Controllerservice/ 实现业务逻辑repository/ 添加数据访问方法(如需要)frontend/src/api/ 添加API调用封装backend/src/main/resources/sql/create.sqlentity/ 实体类frontend/src/views/ 创建Vue组件router/index.js 添加路由配置api/ 添加API调用方法(如需要)application.properties 中的 spring.servlet.multipart.max-file-sizeconfig.js 中的 uploadLimitGlobalExceptionHandler 统一处理异常并返回标准格式