项目上需要用到在线word、excel文档编辑功能,通过游览器在线打开一个远程的word文档编辑保存,这里记录下整合思路。
onlyoffice简介
ONLYOFFICE 是一款开源的办公套件,提供了一系列在线文档编辑和协作工具,适用于团队和个人使用。它支持文档、表格、演示文稿等格式的创建、编辑和共享,类似于 Google Docs、Microsoft Office 365 等办公软件。
官方文档:https://api.onlyoffice.com/zh-CN/docs/docs-api/get-started/basic-concepts/
onlyoffice部署安装
使用onlyoffice我们需要先部署一套文档服务onlyoffice/documentserver
,它是onlyoffice办公套件的核心组件之一,主要用于处理文档的在线编辑和协作功能。它是 ONLYOFFICE 的文档处理服务器,专门负责处理用户上传的文档,支持文档、表格和演示文稿等格式的在线编辑。
这是部署方式选择docker,比较简单一条命令即可:
docker run -i -t -d -p 9097:80 --privileged=true \
--name docserver --restart=always -e TZ=Asia/Shanghai \
-e ALLOW_PRIVATE_IP_ADDRESS=true -e JWT_ENABLED=false \
onlyoffice/documentserver
其中参数JWT_ENABLED=false
是关闭签名校验,内网使用的话关掉整合起来会方便些,参数ALLOW_PRIVATE_IP_ADDRESS
是允许内网IP回调,documentserver本身回调我们的业务系统,如果是内网的IP需要设置这个参数,否则默认回调不到,这里我被坑了半天,一直以为是docker网络配置问题。
VUE整合
这里可以参考官方文档的这一页:https://api.onlyoffice.com/zh-CN/docs/docs-api/get-started/frontend-frameworks/vue/
参考文档按照以下命令可以创建一个vue使用onlyoffice的范例:
# 创建一个名为 _onlyoffice-vue-demo_ 的 Vue.js 3.x 项目
npm create vue@3
# 进入新创建的目录
cd onlyoffice-vue-demo
# 安装 ONLYOFFICE 文档 Vue.js 组件,并使用 _--save_ 将其保存到 _package.json_ 文件中
npm install --save @onlyoffice/document-editor-vue
打开工程将项目中的 ./src/App.vue 文件,并将其内容替换为以下代码:
<template>
<DocumentEditor
id="docEditor"
documentServerUrl="http://192.168.3.96:9097/"
:config="config"
:events_onDocumentReady="onDocumentReady"
:onLoadComponentError="onLoadComponentError"
height="900px"
/>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { DocumentEditor } from "@onlyoffice/document-editor-vue";
export default defineComponent({
name: 'ExampleComponent',
components: {
DocumentEditor
},
data() {
return {
config: {
document: {
fileType: "docx",
key: "Khirz6zTPdfd7",
title: "这是一个测试文档",
url: "https://home.chengpei.top:8443/root/491f72dd4faa38a214dd8bd1ddb552a9.docx"
},
documentType: "word",
editorConfig: {
callbackUrl: "http://192.168.3.213:8080/url-to-callback"
},
// token: "xxxxxxxxxxxx"
}
}
},
methods: {
onDocumentReady() {
console.log("Document is loaded");
},
onLoadComponentError (errorCode, errorDescription) {
switch(errorCode) {
case -1: // Unknown error loading component
console.log(errorDescription);
break;
case -2: // Error load DocsAPI from http://documentserver/
console.log(errorDescription);
break;
case -3: // DocsAPI is not defined
console.log(errorDescription);
break;
}
}
},
});
</script>
这里需要特别注意的几个参数如下:
documentServerUrl: documentserver服务的URL,也就是上面docker搭建的服务
config: 这是当前要编辑的文档的描述配置,包含文档信息(document)、文档类型(documentType)、编辑配置(editorConfig)、签名(token)等
callbackUrl: 保存回调地址,当发生编辑器打开、关闭、强制保存等操作时,会回调我们的业务系统执行对应操作,比如保存文件之类的,这是一个我们业务系统必须实现的接口
token: 签名如果在部署documentserver时配置了JWT_ENABLED=true
则签名是必须传的,签名的计算逻辑参考官方文档:https://api.onlyoffice.com/zh-CN/docs/docs-api/additional-api/signature/
其中config
参数按理说不应该前端这么写死的,config
中的参数全都是当前这个待编辑文件的相关信息,应该直接又后端业务系统返回,比如:页面上展示了一些可编辑文件列表,选择某个文件点击编辑时,后端根据选择的文件组装config信息,包含文件的ID(key)、文件类型(fileType)、文件下载地址(url)等,前端拿到config直接传给DocumentEditor
组建打开一个onlyoffice的文件编辑窗口即可编辑了,文件编辑过程中是自动保存的,文件有变动马上会触发保存,但是这时文件并不是真的保存了,等到窗口关闭时,或者前端调用了强制保存时,documentserver会回调上面配置的callbackUrl
接口,传入以下请求体:
{
"actions": [
{
"type": "DISCONNECTED",
"userid": "uid-1756171298433"
}
],
"changesurl": "http://192.168.3.96:9097/cache/files/data/111ac2d8a0815d729fa9_702/changes.zip/changes.zip?md5=Ojhah6-hu1pd_VOr8-uJrA&expires=1756197053&shardkey=undefined&filename=changes.zip",
"filetype": "docx",
"history": {
"serverVersion": "9.0.4",
"changes": [
{
"documentSha256": "fcffb173437380e77bd16661b2a1be0e71c40bb318184acd64da061b3621c186",
"created": "2025-08-26 08:15:42",
"user": {
"id": "uid-1756171298433",
"name": "Anonymous"
}
}
]
},
"key": "111ac2d8a0815d729fa9",
"status": "SAVE",
"url": "http://192.168.3.96:9097/cache/files/data/111ac2d8a0815d729fa9_702/output.docx/output.docx?md5=raC8B92ncNB4wcvrRz1CkQ&expires=1756197053&shardkey=undefined&filename=output.docx",
"users": [
"uid-1756171298433"
]
}
其中url为修改后的文件,业务系统收到该回调后可以保存该文件,实现业务上的文件保存功能。
前端也可以手动调用接口触发回调强制保存,详细参考官方文档命令服务 - forcesave
后端回调接口实现
这里后端使用springboot,实现以下这个接口即可:
@PostMapping(value = "/url-to-callback")
public String callback(@RequestBody final Callback body) {
log.info("======== url-to-callback ========");
try {
String bodyString = JSONUtil.toJsonStr(body);
if (bodyString.isEmpty()) { // if the request body is empty, an error occurs
throw new RuntimeException("{\"error\":1,\"message\":\"Request payload is empty\"}");
}
log.info(bodyString);
// TODO 判断当前是什么操作什么状态,根据情况保存url里的文件
} catch (Exception e) {
String message = e.getMessage();
if (!message.contains("\"error\":1")) {
log.error("callback Exception", e);
}
return message;
}
return "{\"error\":\"0\"}";
}
Callback
是onlyoffice SDK依赖里的一个类,封装了回调的参数依赖如下:
<dependency>
<groupId>com.onlyoffice</groupId>
<artifactId>docs-integration-sdk</artifactId>
<version>1.4.0</version>
</dependency>
你也可以在回调地址后面拼上?param=xxx传一些自定义的参数,通过@RequestParam
拿到
评论区