# ljy **Repository Path**: boy_lin/ljy ## Basic Information - **Project Name**: ljy - **Description**: 这是一个基于 OnlyOffice Document Server 和 MinIO 对象存储 的在线文档协作系统。用户可以通过 Web 界面上传、预览、 编辑 Office 文档(Word、Excel、PowerPoint 等),所有文档存储在 MinIO 中,通过 OnlyOffice 实现在线协作编辑功能。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2026-08-05 - **Last Updated**: 2026-08-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OnlyOffice + MinIO 在线文档协作系统 - 项目详解 ## 一、项目概述 ### 1.1 项目简介 这是一个基于 **OnlyOffice Document Server** 和 **MinIO 对象存储** 的在线文档协作系统。用户可以通过 Web 界面上传、预览、编辑 Office 文档(Word、Excel、PowerPoint 等),所有文档存储在 MinIO 中,通过 OnlyOffice 实现在线协作编辑功能。 ### 1.2 核心功能 - 📤 **文件上传**:支持拖拽上传多种格式的 Office 文档 - 👁️ **在线预览**:在浏览器中直接预览文档内容 - ✏️ **在线编辑**:支持多人协作编辑文档 - 💾 **自动保存**:编辑完成后自动保存回 MinIO - 🗑️ **文件管理**:支持文件列表查看、搜索、删除等操作 - 🔐 **JWT 安全认证**:使用 JWT 令牌保护 OnlyOffice 回调安全 ### 1.3 技术架构 ``` ┌─────────────────┐ ┌──────────────────┐ ┌───────────────────┐ │ Vue3 前端 │◄────►│ Spring Boot 后端 │◄────►│ OnlyOffice │ │ (onlyoffice-web)│ HTTP │ (onlyoffice) │ HTTP │ Document Server │ │ │ │ │ │ │ └─────────────────┘ └────────┬─────────┘ └───────────────────┘ │ ▼ ┌──────────────────┐ │ MinIO 对象存储 │ │ (文档存储) │ └──────────────────┘ ``` --- ## 二、技术栈详解 ### 2.1 后端技术栈(Spring Boot) | 技术 | 版本 | 用途 | |------|------|------| | **Spring Boot** | 3.3.1 | 核心框架,提供 RESTful API | | **Java** | 17 | 开发语言 | | **MinIO SDK** | 8.4.3 | 对象存储客户端 | | **Hutool JWT** | 5.8.25 | JWT 令牌生成与验证 | | **FastJSON** | 2.0.32 | JSON 数据处理 | | **Lombok** | - | 简化代码(@Data, @Slf4j 等) | ### 2.2 前端技术栈(Vue 3) | 技术 | 版本 | 用途 | |------|------|------| | **Vue 3** | 3.4.31 | 渐进式 JavaScript 框架 | | **Vite** | 5.3.4 | 现代化构建工具 | | **Element Plus** | 2.9.7 | UI 组件库 | | **OnlyOffice Document Editor Vue** | 1.4.0 | OnlyOffice 官方 Vue 组件 | ### 2.3 第三方服务 | 服务 | 用途 | |------|------| | **OnlyOffice Document Server** | 文档在线编辑服务(Docker 部署) | | **MinIO** | 分布式对象存储(Docker 部署) | --- ## 三、项目结构 ``` only-office-minio--java-web-master/ ├── onlyoffice/ # 后端项目根目录 │ ├── onlyoffice/ # Spring Boot 应用 │ │ ├── src/main/java/cn/superlu/onlyoffice/ │ │ │ ├── config/ # 配置类 │ │ │ │ ├── MinioConfig.java # MinIO 客户端配置 │ │ │ │ └── OnlyOfficeConfig.java # OnlyOffice 配置 │ │ │ ├── constant/ # 常量定义 │ │ │ │ └── OnlyOfficeCallBackStatus.java │ │ │ ├── controller/ # REST 控制器 │ │ │ │ ├── OnlyOfficeController.java # 主要 API 接口 │ │ │ │ └── OnlyOffice1Controller.java │ │ │ ├── dto/ # 数据传输对象 │ │ │ │ └── FileInfoDTO.java │ │ │ ├── service/ # 业务逻辑层 │ │ │ │ ├── MinioService.java # MinIO 文件操作 │ │ │ │ └── OnlyOfficeService.java # OnlyOffice 业务逻辑 │ │ │ └── OnlyofficeApplication.java # 启动类 │ │ ├── src/main/resources/ │ │ │ └── application.yml # 应用配置文件 │ │ └── pom.xml # Maven 依赖配置 │ │ │ └── onlyoffice-web/ # Vue3 前端应用 │ ├── src/ │ │ ├── components/ # Vue 组件 │ │ │ ├── FileManager.vue # 文件管理主界面 │ │ │ ├── FileUpload.vue # 文件上传组件 │ │ │ └── OnlyOfficeViewer.vue # OnlyOffice 编辑器组件 │ │ ├── App.vue # 根组件 │ │ └── main.js # 入口文件 │ ├── package.json # npm 依赖配置 │ └── vite.config.js # Vite 构建配置 │ └── README.md # 项目说明文档 ``` --- ## 四、核心业务逻辑 ### 4.1 系统架构图 ``` 用户浏览器 │ ├─→ [Vue 前端] ──HTTP──→ [Spring Boot 后端] ──HTTP──→ [OnlyOffice Document Server] │ │ │ │ │ │ │ │ │ │ ↓ │ │ │ [MinIO 对象存储] ←─────────────────┘ │ │ (文档存储) (回调保存) │ │ └────────┴────────────── 直接访问编辑器界面 ``` ### 4.2 核心业务流程 #### 4.2.1 文件上传流程 ``` 1. 用户在前端选择文件 ↓ 2. 前端通过 /api/onlyoffice/upload 上传到后端 ↓ 3. 后端调用 MinioService.uploadFile() - 生成唯一 fileKey (UUID) - 构建 objectName = fileKey.fileType - 上传到 MinIO 存储桶 ↓ 4. 返回 FileInfoDTO 给前端 - fileName: 原始文件名 - fileUrl: MinIO 预签名 URL - fileType: 文件扩展名 - fileKey: 唯一标识 ``` **关键代码位置:** - 前端:[FileManager.vue](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice-web\src\components\FileManager.vue#L44-L68) 上传对话框 - 后端:[OnlyOfficeService.uploadFile()](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice\src\main\java\cn\superlu\onlyoffice\service\OnlyOfficeService.java#L164-L191) - MinIO 操作:[MinioService.uploadFile()](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice\src\main\java\cn\superlu\onlyoffice\service\MinioService.java#L57-L74) #### 4.2.2 文档预览/编辑流程 ``` 1. 用户点击"预览"或"编辑"按钮 ↓ 2. 前端打开 OnlyOfficeViewer 对话框 ↓ 3. OnlyOfficeViewer 调用 /api/onlyoffice/editor-config 参数:fileUrl, fileName, fileType, fileKey, mode ↓ 4. 后端 OnlyOfficeService.buildEditorConfig() - 构建文档权限配置 - 构建编辑器配置(含回调 URL) - 使用 JWT密钥对整个 config 签名生成 token - 返回包含 token 的完整配置 ↓ 5. 前端将配置传给 DocumentEditor 组件 ↓ 6. OnlyOffice Document Server 加载编辑器 - 从后端代理 URL 获取文档内容 - 展示给用户 ``` **关键代码位置:** - 前端配置请求:[OnlyOfficeViewer.vue](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice-web\src\components\OnlyOfficeViewer.vue#L79-L111) - 后端配置构建:[OnlyOfficeService.buildEditorConfig()](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice\src\main\java\cn\superlu\onlyoffice\service\OnlyOfficeService.java#L73-L139) - JWT 生成:[JWTUtil.createToken()](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice\src\main\java\cn\superlu\onlyoffice\service\OnlyOfficeService.java#L128) #### 4.2.3 文档保存流程(回调机制) ``` OnlyOffice Document Server (用户编辑完成) ↓ 触发回调 POST /api/onlyoffice/callback Body: { status: 2, url: "下载 URL", key: "fileKey", ... } Header: Authorization: Bearer ↓ 后端 OnlyOfficeService.handleCallback() ├─ ① 验证 JWT Token ├─ ② 检查 status (2 或 6 表示需要保存) ├─ ③ 从 OnlyOffice 提供的 url 下载编辑后的文档 ├─ ④ 保存到临时文件 ├─ ⑤ 调用 MinioService.uploadFile() 覆盖原文件 └─ ⑥ 删除临时文件 ↓ 返回 { error: 0 } 给 OnlyOffice ``` **关键代码位置:** - 回调处理:[OnlyOfficeService.handleCallback()](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice\src\main\java\cn\superlu\onlyoffice\service\OnlyOfficeService.java#L201-L285) - JWT 验证:[JWTUtil.verify()](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice\src\main\java\cn\superlu\onlyoffice\service\OnlyOfficeService.java#L211) #### 4.2.4 文件下载代理流程 ``` OnlyOffice Document Server 需要读取文档 ↓ 请求:GET /api/onlyoffice/files/{fileKey.fileType} ↓ 后端 OnlyOfficeController.serveFile() ↓ 调用 MinioService.downloadFile() 获取输入流 ↓ 流式传输给 OnlyOffice(避免 OnlyOffice 直接访问 MinIO) ``` **关键代码位置:** - 代理下载:[OnlyOfficeController.serveFile()](file://e:\project_new\only-office-minio--java-web-master\onlyoffice\onlyoffice\src\main\java\cn\superlu\onlyoffice\controller\OnlyOfficeController.java#L138-L168) --- ## 五、核心配置说明 ### 5.1 后端配置(application.yml) ```yaml # 服务器配置 server: port: 8089 # 后端服务端口 # MinIO 配置 minio: endpoint: http://192.168.2.47:9000 # MinIO 服务地址 access-key: aD5oUWPEcF1JUQzem5N3 # 访问密钥 secret-key: RuC5IPNcpps4G50xdMQDCRuMMgVmFPHSxxAMNPbS # 密钥 bucket-name: nnbl-sys # 存储桶名称 secure: false # 是否使用 HTTPS # OnlyOffice 配置 onlyoffice: document-server-url: http://192.168.2.47:9100/ # Document Server 地址 callback-url: http://192.168.2.47:8089/api/onlyoffice/callback # 回调地址 file-url-prefix: http://192.168.2.47:8089/api/onlyoffice/files/ # 文件代理前缀 jwt-secret: buVfSv20Je2ZbRhck35CHcSL49nRSeG4 # JWT密钥(必须与 OnlyOffice 一致) ``` ### 5.2 前端配置(vite.config.js) ```javascript export default defineConfig({ plugins: [vue()], server: { host: '127.0.0.1', proxy: { '/api': { target: 'http://127.0.0.1:8089', // 后端代理地址 changeOrigin: true, secure: false } } } }) ``` ### 5.3 OnlyOffice 编辑器配置(前端) ```javascript // OnlyOfficeViewer.vue documentServerUrl="http://192.168.2.47:9100/" // Document Server 地址 ``` --- ## 六、API 接口详解 ### 6.1 文件上传接口 **接口:** `POST /api/onlyoffice/upload` **请求参数:** - `file` (MultipartFile): 上传的文件 **响应:** `FileInfoDTO` ```json { "fileName": "test.docx", "fileUrl": "http://minio-server/bucket/abc123.docx", "fileType": "docx", "fileKey": "abc123", "uploadTime": 1234567890 } ``` ### 6.2 编辑器配置接口 **接口:** `GET /api/onlyoffice/editor-config` **请求参数:** - `fileUrl`: 文件访问 URL - `fileName`: 文件名 - `fileType`: 文件扩展名 - `fileKey`: 文档唯一 key - `mode`: 模式(edit/view) **响应:** 包含 JWT token 的编辑器配置 ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "document": { "fileType": "docx", "key": "abc123", "title": "test.docx", "url": "http://backend/api/onlyoffice/files/abc123.docx", "permissions": { "print": true, "download": true, "edit": true } }, "documentType": "word", "editorConfig": { "callbackUrl": "http://backend/api/onlyoffice/callback", "mode": "edit", "lang": "zh-CN", "user": { "id": "user_123", "name": "用户" } } } ``` ### 6.3 OnlyOffice 回调接口 **接口:** `POST /api/onlyoffice/callback` **请求头:** - `Authorization: Bearer ` **请求体:** ```json { "status": 2, "url": "http://onlyoffice/download/xxx", "key": "abc123", "filetype": "docx" } ``` **响应:** ```json { "error": 0 } ``` ### 6.4 文件代理下载接口 **接口:** `GET /api/onlyoffice/files/{objectName:.+}` **路径参数:** - `objectName`: 对象名(格式:fileKey.fileType,如 abc123.docx) **响应:** 文件二进制流 ### 6.5 文件删除接口 **接口:** `DELETE /api/onlyoffice/delete/{objectName:.+}` **路径参数:** - `objectName`: 对象名 **响应:** ```json { "success": true, "message": "文件删除成功" } ``` ### 6.6 文件列表接口 **接口:** `GET /api/onlyoffice/files` **响应:** `List` --- ## 七、JWT 安全机制 ### 7.1 为什么需要 JWT? OnlyOffice Document Server 开启 JWT 后,会: 1. 在回调请求时携带 JWT Token,后端需验证合法性 2. 要求前端在编辑器配置中携带 Token,否则拒绝连接 ### 7.2 JWT 生成流程 ```java // 1. 构建完整的编辑器配置 Map Map config = new LinkedHashMap<>(); config.put("document", document); config.put("documentType", "word"); config.put("editorConfig", editorConfig); // 2. 使用 JWT密钥签名 String jwtSecret = onlyOfficeConfig.getJwtSecret(); String token = JWTUtil.createToken(config, jwtSecret.getBytes(StandardCharsets.UTF_8)); // 3. 将 token 写入配置根节点 config.put("token", token); ``` ### 7.3 JWT 验证流程 ```java // 回调时验证 Token String token = authorizationHeader.substring(7); // 提取 Bearer 后的 token boolean valid = JWTUtil.verify(token, jwtSecret.getBytes(StandardCharsets.UTF_8)); if (!valid) { return "{\"error\":1,\"message\":\"JWT 令牌验证失败\"}"; } ``` ### 7.4 注意事项 ⚠️ **重要:** 后端的 `jwt-secret` 必须与 OnlyOffice Document Server 中的 `jwt.secret` 配置完全一致! --- ## 八、OnlyOffice 文档状态码 | 状态码 | 含义 | 处理逻辑 | |--------|------|----------| | 1 | 正在编辑文档 | 无操作 | | 2 | 文档已准备好保存 | ✅ 下载并保存到 MinIO | | 3 | 发生文档保存错误 | 记录错误日志 | | 4 | 文档已关闭,无更改 | 无操作 | | 6 | 正在编辑,但已保存状态 | ✅ 下载并保存到 MinIO | | 7 | 强制保存时发生错误 | 记录错误日志 | --- ## 九、部署说明 ### 9.1 环境要求 - **Node.js**: 16.0+ - **Java**: 17+ - **Docker**: 用于部署 OnlyOffice 和 MinIO ### 9.2 Docker 部署服务 #### 部署 MinIO ```bash docker run -d \ -p 9000:9000 \ -p 9001:9001 \ --name minio \ -v /data/minio:/data \ -e "MINIO_ROOT_USER=aD5oUWPEcF1JUQzem5N3" \ -e "MINIO_ROOT_PASSWORD=RuC5IPNcpps4G50xdMQDCRuMMgVmFPHSxxAMNPbS" \ minio/minio server /data --console-address ":9001" ``` #### 部署 OnlyOffice Document Server ```bash docker run -d \ -p 9100:80 \ --name onlyoffice \ -e JWT_ENABLED=true \ -e JWT_SECRET=buVfSv20Je2ZbRhck35CHcSL49nRSeG4 \ onlyoffice/documentserver ``` ### 9.3 后端部署 ```bash cd onlyoffice/onlyoffice mvn clean package java -jar target/onlyoffice-0.0.1-SNAPSHOT.jar ``` ### 9.4 前端部署 ```bash cd onlyoffice/onlyoffice-web npm install npm run dev # 开发模式 npm run build # 生产构建 ``` --- ## 十、常见问题排查 ### 10.1 OnlyOffice 无法加载文档 **可能原因:** 1. 后端代理服务未启动 2. OnlyOffice 无法访问后端 `/api/onlyoffice/files/*` 接口 3. JWT Token 配置不一致 **解决方案:** - 检查后端服务是否运行在配置的端口 - 确保 OnlyOffice Document Server 能访问后端地址 - 验证 `jwt-secret` 配置一致 ### 10.2 回调不保存文档 **可能原因:** 1. JWT 验证失败 2. 回调 URL 配置错误 3. 网络不通 **解决方案:** - 查看后端日志,确认 JWT 验证是否通过 - 检查 `onlyoffice.callback-url` 配置是否正确 - 测试 OnlyOffice 到后端的网络连通性 ### 10.3 文件上传失败 **可能原因:** 1. MinIO 服务未启动 2. 存储桶不存在且无创建权限 3. 文件大小超过限制 **解决方案:** - 检查 MinIO 服务状态 - 确认配置的 `access-key` 和 `secret-key` 正确 - 调整 `application.yml` 中的文件大小限制配置 --- ## 十一、扩展建议 ### 11.1 功能扩展 - ✅ 添加用户认证系统 - ✅ 实现文档版本管理 - ✅ 支持更多文件格式 - ✅ 添加文档分享功能 - ✅ 实现协作评论功能 ### 11.2 性能优化 - 使用 CDN 加速 OnlyOffice 静态资源 - MinIO 配置分布式集群 - 后端增加 Redis 缓存 - 文件分片上传 ### 11.3 安全加固 - 启用 HTTPS - 添加 API 访问鉴权 - 实现文件类型白名单 - 增加上传频率限制 --- ## 十二、总结 本项目通过集成 OnlyOffice Document Server 和 MinIO,实现了一个完整的在线文档协作系统。核心优势包括: ✅ **前后端分离**:Vue3 + Spring Boot 架构清晰 ✅ **安全可控**:JWT 令牌保护通信安全 ✅ **高可用性**:MinIO 提供可靠的对象存储 ✅ **易于扩展**:模块化设计便于功能扩展 理解本项目的关键在于掌握三条主线: 1. **文件流**:上传 → MinIO 存储 → 代理下载 → 保存回 MinIO 2. **JWT 流**:生成 Token → 前端传递给 OnlyOffice → 回调时验证 3. **配置流**:后端构建配置 → 前端请求配置 → OnlyOffice 使用配置 希望这份文档能帮助你快速理解项目架构和业务逻辑!