先摘一段官网的描述:ONLYOFFICE 文档 是一个开源办公套件,包括文本文档、电子表格、演示文稿和可填写表单的编辑器。 它提供以下功能:
官网文档中文:
https://api.onlyoffice.com/zh/editors/basic
官网文档英文:
https://api.onlyoffice.com/editors/basic
在线效果如:
word:
excel:
ppt:
创建安装目录
mkdir /app/onlyoffice/DocumentServer/logs -p
mkdir /app/onlyoffice/DocumentServer/data -p
mkdir /app/onlyoffice/DocumentServer/lib -p
mkdir /app/onlyoffice/DocumentServer/db -p
下载镜像
docker pull onlyoffice/documentserver
启动镜像,这里以8088端口对外进行服务,可自行修改
docker run -i -t -d -p 8088:80 --restart=always \
-v /app/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \
-v /app/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \
-v /app/onlyoffice/DocumentServer/lib:/var/lib/onlyoffice \
-v /app/onlyoffice/DocumentServer/db:/var/lib/postgresql -e JWT_SECRET=my_jwt_secret onlyoffice/documentserver
将上面的8088端口开放提供服务
firewall-cmd --zone=public --add-port=8088/tcp --permanent
firewall-cmd --reload
启动docker后要过一小段时间,通过docker ps 查看已经运行的dockerId,复制出来后,执行下面的两条命令:
sudo docker exec {onlyOffice Docker ID} sudo supervisorctl start ds:example
sudo docker exec {onlyOffice Docker ID} sudo sed 's,autostart=false,autostart=true,' -i /etc/supervisor/conf.d/ds-example.conf
示例如:
sudo docker exec a6caa73db3f3 sudo supervisorctl start ds:example
sudo docker exec a6caa73db3f3 sudo sed 's,autostart=false,autostart=true,' -i /etc/supervisor/conf.d/ds-example.conf
http://IP:8088/
可以通过自带的example应用进行测试:http://192.168.56.101:8088/example/
看到以上截图,即安装完成了。
以上安装好OnlyOffice并通过example进行体验在线编辑功能,但如果需要在我们的应用系统中正式使用,还需要进行相应的程序集成,集成主要分前端和后台接口两部分。
参考文档:
https://api.onlyoffice.com/zh/editors/react
yarn add @onlyoffice/document-editor-react
以下为我写的页面样例文件
index.less
html,
body {
margin: 0;
padding: 0;
}
.docx-editor-wrapper {
height: 100vh;
overflow: hidden;
}
OnlyOfficeEditor组件代码:
import React from 'react';
import { DocumentEditor } from "@onlyoffice/document-editor-react";
import './index.less';
const OnlyOfficeEditor = () => {
const onDocumentReady = (event) => {
// 请输入函数体代码
console.log("Document is loaded", event);
};
return (
<div className='docx-editor-wrapper'>
<DocumentEditor
id="docxEditor"
documentServerUrl="http://192.168.56.101:8088"
config={{
"document": {
"fileType": "docx",
"key": "Khirz6zTPdf2dsaazx",
"title": "Example Document Title.docx",
"url": "http://192.168.56.1:8888/getFile",
"permissions": {
"comment": true,
"copy": true,
"download": true,
"edit": true,
"print": true,
"fillForms": true,
"modifyFilter": true,
"modifyContentControl": true,
"review": true,
"commentGroups": {}
}
},
"documentType": "word",
"type": "mobile", //mobile或者desktop,移动端还是桌面端效果
"editorConfig": {
"mode": "edit",
"lang": "zh-CN",
"callbackUrl": "http://192.168.56.1:8888/callback",
"user": {
"id": "liu",
"name": "liu"
},
},
}}
events_onDocumentReady={onDocumentReady}
/>
</div>
);
};
export default OnlyOfficeEditor;
重要属性说明:
documentServerUrl:
在线编辑文档服务器的地址(IP和端口)
config.document.key:
定义服务用来识别文档的唯一文档标识符。如果发送了已知key,则将从缓存中获取文档。 每次编辑和保存文档时,都必须重新生成key。 文档 url 可以用作 key,但不能使用特殊字符,长度限制为 128 个符号。
config.document.url
:定义存储查看或编辑的源文档的绝对URL,自己写的接口用于获取源始文件提供给在线编辑文档服务器(见Java的实现部分
)。
config.editorConfig.callbackUrl:
指定文档存储服务回调的绝对地址,即自己写的后台接口处理器,通过此接口进行回调保存处理编辑后的文件(见Java的实现部分
)。
其他参数详细参考此文档说明:
https://api.onlyoffice.com/zh/editors/config
在App.js中引用OnlyOfficeEditor组件
import React from 'react';
import OnlyOfficeEditor from 'src/components/onlyOfficeEditor';
const App = () => {
return (
<div className='app'>
<OnlyOfficeEditor />
</div>
)
};
export default App;
通过此接口提供给文档编辑服务器进行文档下载。
通过此接口提供进行在线保存后的文档处理。
官网参考:
https://api.onlyoffice.com/zh/editors/callback
在回调接口中status=2
时进行文件的保存处理
OnlyOfficeController.java中包含上面的两个接口代码
package cn.ljhua.onlyoffice.controller;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.Collections;
import javax.servlet.http.HttpServletResponse;
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.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import cn.ljhua.onlyoffice.utils.HttpsKitWithProxyAuth;
import lombok.Getter;
import lombok.Setter;
/**
* @author liujh
*/
@RestController
public class OnlyOfficeController {
private static final String FILE_PATH = "D:/temp/1.docx"; //这里仅写死路径测试
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.OPTIONS})
@GetMapping("/getFile")
public ResponseEntity<byte[]> getFile(HttpServletResponse response) throws IOException {
File file = new File(FILE_PATH);
FileInputStream fileInputStream = null;
InputStream fis = null;
try {
fileInputStream = new FileInputStream(file);
fis = new BufferedInputStream(fileInputStream);
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 替换为实际的文档名称
headers.setContentDispositionFormData("attachment", URLEncoder.encode(file.getName(), "UTF-8"));
return new ResponseEntity<>(buffer, headers, HttpStatus.OK);
} catch (Exception e) {
throw new RuntimeException("e -> ", e);
} finally {
try {
if(fis != null) fis.close();
} catch (Exception e) {
}
try {
if(fileInputStream != null) fileInputStream.close();
} catch (Exception e) {
}
}
}
@CrossOrigin(origins = "*", methods = {RequestMethod.GET,RequestMethod.POST, RequestMethod.OPTIONS})
@PostMapping("/callback")
public ResponseEntity<Object> handleCallback(@RequestBody CallbackData callbackData) {
//状态监听
//参见https://api.onlyoffice.com/editors/callback
Integer status = callbackData.getStatus();
switch (status) {
case 1: {
//document is being edited 文档已经被编辑
break;
}
case 2: {
//document is ready for saving,文档已准备好保存
System.out.println("document is ready for saving");
String url = callbackData.getUrl();
try {
saveFile(url); //保存文件
} catch (Exception e) {
System.out.println("保存文件异常");
}
System.out.println("save success.");
break;
}
case 3: {
//document saving error has occurred,保存出错
break;
}
case 4: {
//document is closed with no changes,未保存退出
break;
}
case 6: {
//document is being edited, but the current document state is saved,编辑保存
}
case 7: {
//error has occurred while force saving the document. 强制保存文档出错
}
default: {
}
}
// 返回响应
return ResponseEntity.<Object>ok(Collections.singletonMap("error", 0));
}
public void saveFile(String downloadUrl) throws URISyntaxException, IOException {
HttpsKitWithProxyAuth.downloadFile(downloadUrl, FILE_PATH);
}
@Setter
@Getter
public static class CallbackData {
/**
* 用户与文档的交互状态。0:用户断开与文档共同编辑的连接;1:新用户连接到文档共同编辑;2:用户单击强制保存按钮
*/
// @IsArray()
// actions?:IActions[] =null;
/**
* 字段已在 4.2 后版本废弃,请使用 history 代替
*/
Object changeshistory;
/**
* 文档变更的历史记录,仅当 status 等于 2 或者 3 时该字段才有值。其中的 serverVersion 字段也是 refreshHistory 方法的入参
*/
Object history;
/**
* 文档编辑的元数据信息,用来跟踪显示文档更改记录,仅当 status 等于 2 或者 2 时该字段才有值。该字段也是 setHistoryData(显示与特定文档版本对应的更改,类似 Git 历史记录)方法的入参
*/
String changesurl;
/**
* url 字段下载的文档扩展名,文件类型默认为 OOXML 格式,如果启用了 assemblyFormatAsOrigin(https://api.onlyoffice.com/editors/save#assemblyFormatAsOrigin) 服务器设置则文件以原始格式保存
*/
String filetype;
/**
* 文档强制保存类型。0:对命令服务(https://api.onlyoffice.com/editors/command/forcesave)执行强制保存;1:每次保存完成时都会执行强制保存请求,仅设置 forcesave 等于 true 时生效;2:强制保存请求由计时器使用服务器中的设置执行。该字段仅 status 等于 7 或者 7 时才有值
*/
Integer forcesavetype;
/**
* 文档标识符,类似 id,在 Onlyoffice 服务内部唯一
*/
String key;
/**
* 文档状态。1:文档编辑中;2:文档已准备好保存;3:文档保存出错;4:文档没有变化无需保存;6:正在编辑文档,但保存了当前文档状态;7:强制保存文档出错
*/
Integer status;
/**
* 已编辑文档的链接,可以通过它下载到最新的文档,仅当 status 等于 2、3、6 或 7 时该字段才有值
*/
String url;
/**
* 自定义参数,对应指令服务的 userdata 字段
*/
Object userdata;
/**
* 打开文档进行编辑的用户标识列表,当文档被修改时,该字段将返回最后编辑文档的用户标识符,当 status 字段等于 2 或者 6 时有值
*/
String[] users;
/**
* 最近保存时间
*/
String lastsave;
/**
* 加密令牌
*/
String token;
}
}
出现该文件版本已变,该页面将被重新加载或者the file version has been changed. the page will be reload.可能是因为你使用的key进行了回调处理,会被认为改变,
解决:更换新的key
,即以下面的key参数进行过callback处理后
后就需要更新了,不能一直用同一个。
github: https://github.com/jxlhljh/onlyOfficeTest.git
gitee: https://gitee.com/jxlhljh/onlyOfficeTest.git