一、OnlyOffice 是什么?为什么选择它?
ONLYOFFICE 是一款开源免费的全功能办公套件,核心优势在于文档在线编辑、实时协同与灵活集成能力,完美适配企业级私有化部署需求。它支持 Word、Excel、PPT、PDF 等主流格式的查看与编辑,还提供 AI 辅助编辑(文本生成、翻译、语法检查)、跨平台协作(内置聊天、音视频通话)、三级加密(静态 / 传输 / 端到端)等进阶功能,且拥有完善的中文文档和活跃社区。
相比 OpenOffice、Office Online,OnlyOffice 的核心竞争力体现在:
- 开源可定制:社区版基于 AGPL 3.0 协议,支持二次开发(如突破 20 人协同限制);
- 集成友好:提供全面的 REST API,支持与 40+ 平台无缝对接(Nextcloud、Moodle 等);
- 协同高效:支持字符级实时协作,多人编辑无冲突,自带修订记录与评论功能;
- 生态完善:覆盖桌面端(Windows/Linux/macOS)、移动端(iOS/Android)与网页端,满足全场景需求。
适合场景:企业内部文档协作平台、SaaS 产品嵌入在线编辑功能、私有化办公系统搭建等。
二、Docker 快速部署 OnlyOffice Docs 服务
Docker 是部署 OnlyOffice 最便捷的方式,无需复杂依赖配置,一键启动完整服务(含文档服务器、数据库)。
前提条件
- 已安装 Docker 与 Docker Compose(推荐 Docker 版本 ≥ 20.10);
- 服务器内存 ≥ 2GB(官方建议,否则编辑时可能卡顿);
- 开放 80 端口(或自定义端口),确保网络可访问。
部署步骤
- 拉取官方镜像
OnlyOffice 文档服务器的官方镜像已包含核心依赖,直接拉取即可:
拉取最新版 OnlyOffice Docs 镜像
docker pull onlyoffice/documentserver
注意:若 Docker Hub 访问受限,可通过国内镜像源同步(如阿里云镜像仓库),避免自行打包镜像(易出现兼容性问题)。
简化版(无需 MySQL,使用内置 SQLite):
docker run --name onlyoffice-docs -d -p 8088:80 --restart=always onlyoffice/documentserver
适合测试环境,生产环境建议用 MySQL 保证数据可靠性。
onlyoffice默认开启token,如果不需要token可以加-e JWT_ENABLED=false
- 验证部署成功
容器启动后(约 1-2 分钟),访问 http://服务器IP:8088,若看到 OnlyOffice 欢迎页面,则部署成功:
常见问题解决
- 权限不足:若容器启动失败,添加 --privileged=true 参数赋予权限;
- 端口占用:修改 -p 映射端口(如 8089:80),避免与其他服务冲突;
- 中文字体缺失:进入容器复制本地中文字体(如 SimHei.ttf)到 /var/www/onlyoffice/documentserver/core-fonts,执行 documentserver-generate-allfonts.sh 刷新缓存。
SpringBoot的集成
在动手写代码前,我们需要先理清集成的核心逻辑,准备好所需环境,避免后续踩坑。
核心原理:OnlyOffice 与 Spring Boot 如何交互?
OnlyOffice 的集成本质是 "前端渲染 + 后端通信" 的组合:
- 前端:通过 OnlyOffice 提供的 JavaScript API,在页面中嵌入文档编辑器组件,负责文档的可视化编辑、格式渲染;
- 后端(Spring Boot) :作为 "中间桥梁",承担三个关键角色:
- 提供文档文件的存储(本地 / 云存储)与访问接口(如下载文档的 URL);
- 处理 OnlyOffice 的回调通知(如文档编辑完成后,接收 OnlyOffice 返回的编辑结果,更新本地文件)。
简单来说:用户在前端编辑文档时,操作会实时同步到 OnlyOffice 服务端;编辑完成后,OnlyOffice 会通知 Spring Boot 后端,后端再从 OnlyOffice 获取最新文档并保存 ------ 整个流程需保证 "文件地址可访问""接口权限合法""回调处理可靠"。
步骤 1:配置 OnlyOffice 服务地址
在 application.properties 中配置 OnlyOffice 服务地址和回调接口地址:
# OnlyOffice Document Server 地址(前端加载编辑器用)
onlyoffice.server.url=http://onlyoffice-ip:8080
# 后端回调接口地址(OnlyOffice 保存文档时调用)
onlyoffice.callback.url=http://your-springboot-ip:8081/api/onlyoffice/callback
# 文档存储路径(本地存储示例)
doc.storage.path=/app/documents/
步骤 2:后端核心接口实现
2.1 文档配置接口(给前端返回编辑器参数)
前端加载 OnlyOffice 编辑器时,需要从后端获取文档的配置信息(如文件地址、权限、回调地址等)。
java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/onlyoffice")
public class OnlyOfficeController {
@Value("${onlyoffice.server.url}")
private String onlyofficeServerUrl;
@Value("${onlyoffice.callback.url}")
private String callbackUrl;
@Value("${doc.storage.path}")
private String docStoragePath;
// 文档配置接口:前端请求此接口获取编辑器参数
@GetMapping("/config")
public Map<String, Object> getDocConfig(@RequestParam String fileName) throws Exception {
// 1. 构建文档访问地址(后端提供的文档下载地址)
String docUrl = "http://your-springboot-ip:8081/api/doc/download?fileName=" + fileName;
// 2. 配置 OnlyOffice 编辑器参数
Map<String, Object> config = new HashMap<>();
config.put("document", Map.of(
"fileType", fileName.split("\\.")[1], // 文档类型(如 docx、xlsx)
"key", fileName, // 文档唯一标识(建议用文件MD5或UUID)
"title", fileName,
"url", docUrl // 文档下载地址(OnlyOffice 会从这里拉取文件)
));
// 3. 配置编辑器权限(是否可编辑)
config.put("editorConfig", Map.of(
"callbackUrl", callbackUrl, // 保存回调地址
"user", Map.of("id", "1", "name", "张三"), // 当前用户信息
"mode", "edit" // 模式:edit(编辑)/ view(查看)
));
// 4. 配置 OnlyOffice 服务地址
config.put("documentServerUrl", onlyofficeServerUrl);
return config;
}
}
2.2 文档下载接口(OnlyOffice 拉取文件用)
OnlyOffice 编辑器需要从后端下载文档进行编辑,因此需要提供一个下载接口:
java
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
@RestController
@RequestMapping("/api/doc")
public class DocController {
@Value("${doc.storage.path}")
private String docStoragePath;
// 文档下载接口:OnlyOffice 从这里拉取文件
@GetMapping("/download")
public ResponseEntity<byte[]> downloadDoc(@RequestParam String fileName) throws Exception {
File docFile = new File(docStoragePath + fileName);
if (!docFile.exists()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
// 设置响应头(指定文件类型)
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", fileName);
return new ResponseEntity<>(FileUtils.readFileToByteArray(docFile), headers, HttpStatus.OK);
}
}
2.3 回调接口(OnlyOffice 保存文档时调用)
当用户编辑完成并点击保存后,OnlyOffice 会将编辑后的文档通过回调接口发送到后端,后端需要接收并保存文件。
java
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.net.URL;
@RestController
@RequestMapping("/api/onlyoffice")
public class OnlyOfficeCallbackController {
@Value("${doc.storage.path}")
private String docStoragePath;
private final ObjectMapper objectMapper = new ObjectMapper();
// 回调接口:OnlyOffice 保存文档时调用
@PostMapping("/callback")
public ResponseEntity<String> callback(@RequestBody JsonNode body) throws Exception {
// 1. 解析回调参数
String status = body.get("status").asText(); // 状态:2 - 已保存,3 - 保存并关闭
if (!"2".equals(status) && !"3".equals(status)) return ResponseEntity.ok("{\"error\":0}");
String url = body.get("url").asText(); // 编辑后文档的临时URL(OnlyOffice 提供)
String fileName = body.get("key").asText(); // 文档唯一标识(与配置中的key一致)
// 2. 状态为2或3时,下载并保存文档
if ("2".equals(status) || "3".equals(status)) {
// 从 OnlyOffice 提供的临时URL下载编辑后的文件
File editedFile = new File(docStoragePath + fileName);
FileUtils.copyURLToFile(new URL(url), editedFile);
}
// 3. 必须返回 {"error":0},否则 OnlyOffice 会认为回调失败并重复调用
return ResponseEntity.ok("{\"error\":0}");
}
}
步骤 3:前端页面集成 OnlyOffice 编辑器
前端需要引入 OnlyOffice 的 JS 脚本,并通过后端返回的配置信息初始化编辑器。
示例(HTML + JavaScript):
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>OnlyOffice 编辑示例</title>
<!-- 引入 OnlyOffice 编辑器脚本(地址为部署的 Document Server) -->
<script src="http://onlyoffice-ip:8080/web-apps/apps/api/documents/api.js"></script>
</head>
<body>
<!-- 编辑器容器 -->
<div id="onlyofficeEditor" style="width: 100%; height: 800px;"></div>
<script>
// 从后端获取文档配置
fetch('http://your-springboot-ip:8081/api/onlyoffice/config?fileName=test.docx')
.then(response => response.json())
.then(config => {
// 初始化 OnlyOffice 编辑器
new DocsAPI.DocEditor("onlyofficeEditor", config);
});
</script>
</body>
</html>