OnlyOffice 文档服务集成指南
用途:说明 RuoYi Office 为何依赖 OnlyOffice Document Server、如何部署、如何配置、以及依赖它的业务功能如何使用。 适用版本:
onlyoffice/documentserver:8.2。
1. 这是什么依赖、为什么需要
RuoYi Office 的 合同模板 / 合同正文「高保真在线编辑」 依赖 OnlyOffice Document Server。
- 解决的问题:早期合同正文走
mammoth.js(docx → HTML)+ TinyMCE 富文本,会丢弃 Word 的直接格式(标题居中/字号、首行缩进、两端对齐、复杂编号等),导入后排版与原文不一致,且调参无法根治。 - 选型结论:OnlyOffice 是「真·在线 Word」,docx 预览/编辑/导出完美往返,是「自由在线编辑 + 高保真」的行业标准方案。
- 可选依赖:OnlyOffice 是可选组件。未部署或未开启时,系统自动降级为 HTML 富文本编辑,业务不中断;部署并开启后即获得高保真能力。
| 维度 | 说明 |
|---|---|
| 依赖组件 | OnlyOffice Document Server(Docker,约 2GB+ 镜像) |
| 依赖它的功能 | 合同模板配置、合同正文在线编辑与预览 |
| 是否必需 | 否,可选;未部署自动降级 HTML 富文本 |
| 后端集成模块 | ruoyi-office/yudao-module-contract |
| 前端集成位置 | ruoyi-office-vben/apps/web-antd/src/views/contract |
2. 架构与数据流
浏览器(管理端) 后端(yudao) OnlyOffice Document Server
│ ① GET /contract/onlyoffice/config │ │
│ ─────────────────────────────────>│ 构建配置 + JWT 签名 │
│ <──────── config(含 token) ────────│ │
│ ② 加载 api.js,new DocEditor(config)─────────────────────────────>│
│ │ ③ GET /download?token= (拉原文)
│ │<─────────────────────────────│
│ (用户在线编辑) │ │
│ │ ④ POST /callback?token= (回存)
│ │<─────────────────────────────│
│ │ 下载编辑后文件→FileApi 存储 │
│ │ 回写 contract_template.doc_file_url三个关键地址(务必区分「视角」,配错必然打不开或不保存):
| 配置项 | 视角 | 含义 |
|---|---|---|
server-url | 浏览器视角 | 浏览器加载 api.js 的文档服务器地址,浏览器必须能直接访问 |
callback-base-url | 容器视角 | OnlyOffice 容器回访后端(拉原文 / 回存)的地址,容器内必须能访问到后端 |
jwt-secret | 双方约定 | 后端与容器 JWT_SECRET 必须完全一致,否则 token 互不认 |
下载
/download与回调/callback接口用 JWT 令牌自校验(@PermitAll + @TenantIgnore),无需登录态;编辑器配置整体用JWT_SECRET签名(config.token)。
3. 部署 Document Server(Docker)
仓库已提供 compose 文件:ruoyi-office/script/docker/docker-compose.onlyoffice.yml。
3.1 启动
# 将 docker-compose.onlyoffice.yml 拷贝到目标主机(如 /data/onlyoffice/)后:
cd /data/onlyoffice
docker compose -f docker-compose.onlyoffice.yml up -d
# 跟踪启动日志,出现就绪信息后 Ctrl+C
docker logs -f onlyoffice-documentserver启动后访问 http://<宿主机IP>:8081/,出现 ONLYOFFICE 欢迎页即成功。
compose 关键点:
services:
onlyoffice-documentserver:
image: onlyoffice/documentserver:8.2
ports:
- '8081:80' # 宿主机 8081 → 容器 80
environment:
- JWT_ENABLED=true
- JWT_SECRET=ruoyi-office-onlyoffice-secret # 必须与后端 jwt-secret 一致
- JWT_HEADER=Authorization
ulimits:
core: 0 # 禁止 core dump(防磁盘被撑爆,见第 8 节)
logging:
driver: 'json-file'
options: { max-size: '10m', max-file: '3' }3.2 镜像拉取失败(国内网络)
若报 registry-1.docker.io ... Timeout,任选其一:
- 配镜像加速:写
/etc/docker/daemon.json的registry-mirrors后systemctl restart docker。 - 换源手动拉取 + 打标签:如从华为云
swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/onlyoffice/documentserver:8.2拉取后docker tag回onlyoffice/documentserver:8.2。 - 离线导入:能上网的机器
docker save成 tar,scp到目标机docker load。
详细命令见文末「演示环境部署实战」文档 3.1 节。
4. 后端配置(application.yaml)
在后端配置文件的 yudao 段下配置:
yudao:
onlyoffice:
enabled: true # 部署好后改为 true 启用高保真
server-url: http://localhost:8081 # 【浏览器视角】文档服务器地址
jwt-secret: ruoyi-office-onlyoffice-secret # 必须与容器 JWT_SECRET 完全一致
callback-base-url: http://host.docker.internal:48080 # 【容器视角】回访后端地址不同环境的填法:
| 环境 | server-url(浏览器视角) | callback-base-url(容器视角) |
|---|---|---|
| 本机 Windows/Mac 开发 | http://localhost:8081 | http://host.docker.internal:48080(compose 需开启 extra_hosts) |
| Linux 单机 / 同宿主机 | http://<后端可达域名或IP>:8081 | http://<宿主机内网IP>:48080 |
| 公网直连(如演示环境) | http://<域名>:<映射端口>(如 http://ruoyioffice.com:18081) | http://<后端内网IP>:48080 |
要点:
callback-base-url不要带/admin-api后缀、不要带末尾/,后端会自动拼/admin-api/contract/onlyoffice/...。- Linux 用
host.docker.internal时,给 compose 服务加extra_hosts: ['host.docker.internal:host-gateway']。 - 生产建议
server-url使用域名;前端为 HTTPS 时server-url也必须 HTTPS(否则混合内容被浏览器拦截)。 - 修改配置后重启后端使其生效。
5. JWT 与回调自检(最易踩坑,必做)
① JWT secret 自检 —— OnlyOffice 8.x 默认开启 JWT,若容器不是用本仓库 compose 启动,会自动生成随机 secret,导致「token 无效 / 文档打不开」:
# 应输出 ruoyi-office-onlyoffice-secret
docker exec onlyoffice-documentserver /var/www/onlyoffice/documentserver/npm/json \
-f /etc/onlyoffice/documentserver/local.json 'services.CoAuthoring.secret.session.string'不一致就用本仓库 compose 重建容器(down 后 up -d)。
② 回调连通性自检 —— 「能打开但不保存」多半是容器访问不到后端:
docker exec -it onlyoffice-documentserver bash
curl -I "http://<callback-base-url 的 host:port>/admin-api/contract/onlyoffice/enabled"
# 期望网络可达(200/401 均可,重点是不能 Connection refused / timeout)
exit6. 集成点(供二开了解)
后端接口(前缀 /admin-api):
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| GET | /contract/onlyoffice/enabled | 登录 | 是否启用高保真 |
| GET | /contract/onlyoffice/config | 登录 | 获取编辑器配置(含签名 token) |
| GET | /contract/onlyoffice/download | 放行(JWT) | 供文档服务器拉原文 |
| POST | /contract/onlyoffice/callback | 放行(JWT) | 文档服务器保存回调 |
关键类 / 文件:
| 位置 | 说明 |
|---|---|
framework/onlyoffice/config/OnlyOfficeProperties | yudao.onlyoffice.* 配置绑定 |
service/onlyoffice/OnlyOfficeServiceImpl | 构建配置 + JWT、下载、回调回存 |
controller/admin/onlyoffice/OnlyOfficeController | enabled / config / download / callback |
src/api/contract/onlyoffice/index.ts | 前端 isOnlyOfficeEnabled / getOnlyOfficeConfig |
src/components/onlyoffice-editor/index.vue | 动态加载 api.js + new DocsAPI.DocEditor |
7. 使用指南(业务功能)
部署并 enabled: true 后,依赖 OnlyOffice 的业务功能即可使用:
- 配置合同模板:合同 → 合同配置 → 合同模板 → 「配置」。上传/含有 Word 源文件的模板会默认进入高保真在线编辑(OnlyOffice iframe);右上角可在「高保真(Word) / 富文本(HTML)」间切换。
- 在线编辑与自动保存:Word 模式下由文档服务器自动保存(autosave + forcesave),无需手动点保存;编辑后系统把文件存为新版本并回写模板源文件地址。
- 占位符:在 Word 中以
文本标注占位符(排版 100% 保留)。合同起草选模板时,后端用占位值做文本替换生成正文,再用 OnlyOffice 预览/编辑。 - 合同起草生成:合同起草 → 选择模板 → 生成正文(占位符已填充)→ 提交审批。
- 台账预览:合同台账中点击「合同文件」弹窗预览生成的 Word/PDF(私有 OSS 走预签名,不报 AccessDenied)。
未部署 OnlyOffice 时,以上编辑环节自动降级为 HTML 富文本,格式保真度较低,但功能可用。
8. 磁盘占用防范(重要)
OnlyOffice 容器有两类「吃磁盘」来源,本仓库 compose 已内置防范:
- core dump:转换/文档进程崩溃会生成 GB 级 core 文件,反复崩则反复生成 →
ulimits.core: 0禁止。 - 容器日志膨胀:stdout/stderr 被 json-file 无限累积 →
logging限制max-size: 10m/max-file: 3。
Windows 本地还会叠加 WSL2
ext4.vhdx只增不减的问题(生产 Linux 无此问题)。本地止血:停容器 →.wslconfig设coreDump=false→wsl --shutdown→ 压缩 vhdx。详见演示环境文档第 9 节。
9. 常见问题
| 现象 | 排查 |
|---|---|
| 编辑器空白 / 一直转圈 | docker ps 确认容器 Up;浏览器能否打开 server-url 欢迎页 |
| api.js 加载失败 | server-url 浏览器是否可达;端口/安全组是否放行;是否被混合内容(HTTP/HTTPS)拦截 |
| 提示 token 无效 / 文档打不开 | 第 5 节 ①:容器实际 secret 是否 = 后端 jwt-secret;后端是否重启 |
| 能打开但不保存 | 第 5 节 ②:容器能否访问 callback-base-url;后端日志搜 [onlyoffice callback] |
| 中文乱码 | 集成已设 lang=zh-CN,检查容器时区/语言 |
