最近研究了一下onlyoffice的开发一个在线协同编辑的小功能,在网上也找了很多博客,非常感谢一个老哥的知道,这里贴出他博客的地址:如何在 Windows 上 使用 ONLYOFFICE 协作编辑文档这个博客的作者已经开源了一套比较成熟的onlyoffice二次开发的系统,环境安装完毕后可直接运行使用。因为我这边的需求是要自己使用java后台集成一些所以,在开发过程中也请教了好多前边那个大神的很多问题,也都一一耐心的指导。好了话不多说了。
        我的小Demo已经上传到码云:https://gitee.com/lei223/onlyofficeDemo,欢迎有需要的同学下载。里边包含了前后台的源码,数据库使用的sqlite 前端用的vue基础项目。欢迎下载。下面开始我的集成步骤了。安装过程看上述大神的教程即可。
        1》Controller类

@Slf4j
@Controller
public class FileController {@Value("${files.savePath}")private String filePath;@Value("${files.docservice.url.site}")private String officeUrl;@Value("${files.docservice.url.command}")private String officeCommand;@Autowiredprivate DocumentService documentService;@Autowiredprivate FileUploadService uploadService;@AutowiredRestTemplate restTemplate;@ResponseBody@PostMapping(value = "upload")public ResponseEntity<Object> upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {if (file.isEmpty()) {throw new Exception("上传文件不能为空");}FileUpload upload = new FileUpload();String fileName = file.getOriginalFilename();
//        if (!fileName.endsWith("xls") && !fileName.endsWith("xlsx")) {
//            throw new Exception("请上传Excel文件");
//        }//更新保存文件信息到数据库FileUtil.saveFile(file.getInputStream(), filePath + file.getOriginalFilename());
//        System.out.println(fileName);upload.setUpload_date(new Date());System.out.println(".".indexOf(fileName));System.out.println(fileName.length());upload.setFile_type(fileName.substring(fileName.indexOf(".")));upload.setFile_path(filePath);upload.setFile_name(file.getOriginalFilename());upload.setFile_size(file.getSize());uploadService.save(upload);//操作人
//        String operator=request.getAttribute(StrUtil.USER_WORKNUMBER).toString();
//        xxxService.saveUploadCkdExecl(file,operator);return new ResponseEntity<Object>("上传成功", HttpStatus.OK);}/*** \* 查询所有上传文档信息接口** @return*/@GetMapping("/filelist")public ResponseEntity<Object> listFile() {return new ResponseEntity<Object>(uploadService.list(), HttpStatus.OK);}//    public ResponseEntity<Object>  rview(){
//
//    }/*** 下载文档接口* @param name* @param response*/@GetMapping("/download")public void download(String name, HttpServletResponse response) {try {FileUtil.downLoadFile(name,filePath,response);} catch (IOException e) {e.printStackTrace();}}@GetMapping("/edit")public String editDocFile(@RequestParam String name,String userName,String userId,Model model) {String path = filePath+name;
//        String name = "cc.docx";Document document = documentService.getDocument(documentService.buildDocument(path, name));model.addAttribute("document", document);// 如果该格式不支持编辑,则返回预览页面if (!documentService.canEdit(document)) {return "/demo";}model.addAttribute("documentEditParam", documentService.buildDocumentEditParam(userId, userName,name));return "/editor";}/*** 编辑文档时回调接口* @param request* @param response* @throws IOException*/@RequestMapping("/callback")public void saveDocumentFile(HttpServletRequest request, HttpServletResponse response) throws IOException {//处理编辑回调逻辑callBack(request, response);}/**** @return*/@GetMapping("/editStatus")public  ResponseEntity<Object> getDoucmentEditStatus(String name) throws ParseException {String url = officeUrl+officeCommand;Map<String,String>  map = new HashMap<String,String>();map.put("c", "forcesave");String docFileMd5 = Md5Utils.getFileMd5(new File(filePath+name));if (StringUtils.isBlank(docFileMd5)) {throw new DocumentException(ErrorCodeEnum.DOC_FILE_MD5_ERROR);}String pathShortMd5 = Md5Utils.md5(filePath + name);String nameShortMd5 = Md5Utils.md5(name);Hashids hashids = new Hashids(DocumentConstants.HASH_KEY);// (将路径字符串短md5值 + 名称字符串短md5值) ==> 再转成短id形式 ==> 作为文档的key(暂且认为是不会重复的)String key = hashids.encodeHex(String.format("%s%s%s", docFileMd5,pathShortMd5, nameShortMd5));map.put("key", key);map.put("userdata", "sample userdata");JSONObject obj = (JSONObject) new JSONParser().parse(FileUtil.editStatus(url, JSON.toJSONString(map)));return new ResponseEntity<Object>(obj, HttpStatus.OK);}/*** 处理在线编辑文档的逻辑* @param request* @param response* @throws IOException*/private void callBack(HttpServletRequest request, HttpServletResponse response) throws IOException {PrintWriter writer = null;JSONObject jsonObj = null;System.out.println("===saveeditedfile------------");try {writer = response.getWriter();Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");String body = scanner.hasNext() ? scanner.next() : "";jsonObj = (JSONObject) new JSONParser().parse(body);System.out.println(jsonObj);System.out.println("===saveeditedfile:" + jsonObj.get("status"));/*0 - no document with the key identifier could be found,1 - document is being edited,2 - document is ready for saving,3 - document saving error has occurred,4 - document is closed with no changes,6 - document is being edited, but the current document state is saved,7 - error has occurred while force saving the document.* */if ((long) jsonObj.get("status") == 2) {FileUtil.callBackSaveDocument(jsonObj,filePath,request, response);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}/** status = 1,我们给onlyoffice的服务返回{"error":"0"}的信息,这样onlyoffice会认为回调接口是没问题的,这样就可以在线编辑文档了,否则的话会弹出窗口说明* 在线编辑还没有关闭,前端有人下载文档时,强制保存最新内容  当status 是6时说明有人在编辑时下载文档* */System.out.println(jsonObj.get("status"));if ((long) jsonObj.get("status") == 6) {//处理当文档正在编辑为关闭时,下载文档if (((String)jsonObj.get("userdata")).equals("sample userdata")){FileUtil.callBackSaveDocument(jsonObj,filePath,request, response);}System.out.println("====保存失败:");writer.write("{\"error\":1}");} else {//执行删除编辑时下载保存的文件:FileUtil.deleteTempFile(filePath,request.getParameter("fileName"));writer.write("{\"error\":0}");}}}

此类的主要接口有四个集成onlyoffice的在线协同编辑功能:

1》 /edit 此接口是返回给前端onlyoffice的编辑界面并打开要编辑的文件

2》 /download 下载文件接口,onlyoffice需要的接口之一,当将文档参数传入到onlyoffice服务器时需要一个download 的url 来让onlyoffice将文件下载到服务器配置参数如下:

3》/callback 接口 此接口是onlyoffice服务器对于你这服务的回调接口,当打开文档时,编辑完成后保存文档,或是正在编辑时,下载文档调用onlyoffice的强制保存命令之后都会回调这个接口。

4》  /editStatus 获取文档的编辑状态,用于编辑时下载文档,如果用户下载的文档正在被编辑,就可以先调用此接口,向onlyoffice服务器发送强制保存的命令,然后会调用callback接口进行保存。

以上的四个接口是,demo对于onlyoffice服务器的大部分的集成逻辑都在这几个接口的实现细节里。当然还有另外的,上传文件接口和提供文件列表查询的接口。

2。详细介绍一下协作编辑接口的实现逻辑/edit

1》 首先需要了解到如果想要打开一个编辑界面必须遵循onlyoffice文档中的前端文档要求

config = {"document": {"fileType": "docx","key": "Khirz6zTPdfd7","title": "Example Document Title.docx","url": "https://example.com/url-to-example-document.docx"},"documentType": "word","editorConfig": {"callbackUrl": "https://example.com/url-to-callback.ashx"}
};var docEditor = new DocsAPI.DocEditor("placeholder", config);

上述的config 对象就是 打开文本编辑器最基本的配置。/edit 接口的内容就是构建了上述config配置的过程。其中key参数,是一个文档能否多人协同编辑的一个关键点,也就是说多人同事操作的同一个文档时,此时文档的key值肯定是同一个,demo使用算法保持同一个文件key值的唯一。 document下的url 参数就是下载接口的路径   在demo中的接口地址是 /download  config下的editorConfig 是相关回调的配置,其中callbackUrl 代表编辑完成以后 文档将要保存,并将最后结果返回给onlyOffice服务器,onlyoffice服务器需要我们的服务器给它响应为 {"error":0}的响应结果来通知服务器此文档没有问题,否则刚开始无法正常编辑文档。

2》 /edit 的就是做了上述相关配置的构建。具体的实现细节看代码便知。

3.   /download接口的实现:

上图是下载接口的实现逻辑。

4. /callback实现逻辑:

@RequestMapping("/callback")
public void saveDocumentFile(HttpServletRequest request, HttpServletResponse response) throws IOException {PrintWriter writer = null;JSONObject jsonObj = null;System.out.println("===saveeditedfile------------");try {writer = response.getWriter();Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");String body = scanner.hasNext() ? scanner.next() : "";jsonObj = (JSONObject) new JSONParser().parse(body);System.out.println(jsonObj);System.out.println("===saveeditedfile:" + jsonObj.get("status"));/*0 - no document with the key identifier could be found,1 - document is being edited,2 - document is ready for saving,3 - document saving error has occurred,4 - document is closed with no changes,6 - document is being edited, but the current document state is saved,7 - error has occurred while force saving the document.* */if ((long) jsonObj.get("status") == 2) {FileUtil.callBackSaveDocument(jsonObj,filePath,request, response);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}/** status = 1,我们给onlyoffice的服务返回{"error":"0"}的信息,这样onlyoffice会认为回调接口是没问题的,这样就可以在线编辑文档了,否则的话会弹出窗口说明* 在线编辑还没有关闭,前端有人下载文档时,强制保存最新内容  当status 是6时说明有人在编辑时下载文档* */System.out.println(jsonObj.get("status"));if ((long) jsonObj.get("status") == 6) {//处理当文档正在编辑为关闭时,下载文档if (((String)jsonObj.get("userdata")).equals("sample userdata")){FileUtil.callBackSaveDocument(jsonObj,filePath,request, response);}System.out.println("====保存失败:");writer.write("{\"error\":1}");} else {//执行删除编辑时下载保存的文件:FileUtil.deleteTempFile(filePath,request.getParameter("fileName"));writer.write("{\"error\":0}");}}

因为有点长一张截图放不下,此代码是当编辑回调后保存文件。此代码是摘自onlyoffice官方文档的中javasample中的代码.官方地址是sample 加入了自己保存逻辑。实现在编辑时,有人下载也能保存文档。保存文档操作的逻辑如下:

/*** 编辑以后保存文件* @param jsonObj* @param filePath* @param request* @param response* @throws IOException*/
public static void callBackSaveDocument(JSONObject jsonObj, String filePath, HttpServletRequest request, HttpServletResponse response) throws IOException {/** 当我们关闭编辑窗口后,十秒钟左右onlyoffice会将它存储的我们的编辑后的文件,,此时status = 2,通过request发给我们,我们需要做的就是接收到文件然后回写该文件。* *//** 定义要与文档存储服务保存的编辑文档的链接。当状态值仅等于2或3时,存在链路。* */String downloadUri = (String) jsonObj.get("url");System.out.println("====文档编辑完成,现在开始保存编辑后的文档,其下载地址为:" + downloadUri);//解析得出文件名//String fileName = downloadUri.substring(downloadUri.lastIndexOf('/')+1);String fileName = request.getParameter("fileName");System.out.println("====下载的文件名:" + fileName);URL url = new URL(downloadUri);java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();InputStream stream = connection.getInputStream();File savedFile = new File(filePath + fileName);//判断是否包含userdata字段信息,如果有证明前端在编辑文档没有关闭时下载正在在线编辑的文档,// 此时将文件保存为带一个前缀 v1的文档供前端下载。  如 v1xxx.docxif (null!=((String) jsonObj.get("userdata"))&&((String) jsonObj.get("userdata")).equals("sample userdata")) {savedFile = new File(filePath + "v1" + fileName);}try (FileOutputStream out = new FileOutputStream(savedFile)) {int read;final byte[] bytes = new byte[1024];while ((read = stream.read(bytes)) != -1) {out.write(bytes, 0, read);}out.flush();}connection.disconnect();
}

5. /editStatus 接口的实现

FileUtil.editStatus方法具体实现

  /*** 发送网路请求查看是否正在编辑* @param path* @param params* @return*/public static String editStatus(String path, String params) {OutputStreamWriter out = null;BufferedReader in = null;StringBuilder result = new StringBuilder();HttpURLConnection conn = null;try {URL url = new URL(path);conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("POST");//发送POST请求必须设置为trueconn.setDoOutput(true);conn.setDoInput(true);//设置连接超时时间和读取超时时间conn.setConnectTimeout(30000);conn.setReadTimeout(10000);conn.setRequestProperty("Content-Type", "application/json");conn.setRequestProperty("Accept", "application/json");//获取输出流out = new OutputStreamWriter(conn.getOutputStream());
//            String jsonStr = "{\"c\":\"forcesave\", \"key\":\"WpP7m85eNQSEOoepp31oIYVG2oJyJJcvkLdoywgvs1k3ywm3Omuxk4\",\"userdata\":\"sample userdata\"}";out.write(params);out.flush();out.close();//取得输入流,并使用Reader读取if (200 == conn.getResponseCode()) {return IOUtils.toString(conn.getInputStream());} else {System.out.println("ResponseCode is an error code:" + conn.getResponseCode());}} catch (Exception e) {e.printStackTrace();} finally {try {if (out != null) {out.close();}if (in != null) {in.close();}} catch (IOException ioe) {ioe.printStackTrace();}}return "";}

发送完请求以后,onlyoffice就会调用回调接口 进行文件强制保存就会触发callback接口中的这一步逻辑:

此demo具体实现逻辑就是上述。

下边说下修改配置 然后运行起来。

先说前端配置。将请求url中的ip加端口都替换成你本地服务的ip+端口

修改 java工程中的url配置:url的配置全部在application.yml中:

如果确保上树的修改都已经做了,就可以运行前后台的项目了

基于springboot二次开发onlyoffice的Demo相关推荐

  1. 基于Springboot+VUE框架开发的企业微信SCRM系统

    应用介绍 基于Springboot+ vue框架开发的企业微信SCRM 系统是一款基于人工智能的企业微信SCRM系统,企业微信SCRM系统基于企业微信开放能力,不仅集成了企微基础的客户管理和后台管理功 ...

  2. 基于PbootCMS二次开发版,集成常用二次开发功能

    原文链接:基于PbootCMS二次开发版,集成常用二次开发功能 相关说明 基于PbootCMS二次开发,优化后台体验,集成常用功能 不涉及对原PbootCMS授权机制改动或破解,用户使用仍需遵守其相关 ...

  3. catia三维轴承_浅谈基于CATIA二次开发的单排四点接触球轴承三维设计论文

    浅谈基于CATIA二次开发的单排四点接触球轴承三维设计论文 一.概述 单排四点接触球转盘轴承是一种能够同时承受较大轴向负荷.径向负荷和倾覆力矩等综合载荷,集支承.旋转.传动.固定等多种功能于一身的特殊 ...

  4. abaqus python二次开发攻略_基于CAE二次开发进行弹簧批量建模

    一. 为什么要进行弹簧批量建模 当一个公司或者学者从事科研任务时,往往通过有限元进行建模分析,建模的时间通常与工作效率挂钩.例如ABAQUS/CAE建模,想必很多老用户都有某种共同的感受,那就是实体模 ...

  5. 基于ZFAKA二次开发,添加PayJS支付渠道

    基于ZFAKA二次开发,添加PayJS支付渠道 项目地址:https://github.com/hiyouli/payjs-for-zfaka 关于ZFAKA,请移步:ZFAKA 免费.安全.稳定.高 ...

  6. 基于ARCGIS二次开发可视化开发环境搭建(JAVA)

    这两天为了搭建这么一个基于java的ArcGIS二次开发环境可着实花了一番心血.在网上搜索各种资料,大部分都是基于C#的,关于JAVA的很少,而且很杂乱,没有一个完整的.详细的.适合新手的这么一个教程 ...

  7. 基于EasyNVR二次开发实现自己的摄像机IPC/NVR无插件化直播解决方案

    基于EasyNVR二次开发实现自己的摄像机IPC/NVR无插件化直播解决方案 参考文章: (1)基于EasyNVR二次开发实现自己的摄像机IPC/NVR无插件化直播解决方案 (2)https://ww ...

  8. 基于SpringBoot+Mybaits框架开发的OA自动化办公系统Java源码

    源码介绍 办公自动化(OA)是面向组织的日常运作和管理,员工及管理者使用频率最高的应用系统,极大提高公司的办公效率.基于SpringBoot+Mybaits框架开发的OA自动化办公系统Java源码,基 ...

  9. 基于ABAQUS二次开发的仿真分析平台

    ✨基于ABAQUS二次开发的仿真分析平台✨ 随着近年来计算机领域里程碑式的进步,计算机软件市场的迅速扩张,推出了许多功能强大的计算机仿真软件.ABAQUS有限元仿真分析软件则是其中的翘楚,作为应用广泛 ...

最新文章

  1. 华为发布面向2025十大趋势
  2. c++中new和delete的使用方法
  3. 服务器电源can协议,硬件接口协议之“CAN总线EMC设计”
  4. 病毒周报(100111至100117)
  5. unreported exception java.lang.Exception; must be caught or declared to be thrown
  6. Java顶尖程序员需要看的书
  7. 一个SQL逻辑读异常的解决方法
  8. Android Q 不叫 Q,正式命名为 Android 10
  9. CSS表单元素样式设置
  10. Codeforces 964B(贪心)
  11. [leetcode]5-Longest Palindromic Substring
  12. 京东风格的移动端Vue组件库NutUI2.0来啦
  13. 联想E430c:To interrupt normal starup,press enter问题解决方法
  14. java学生管理系统界面设计
  15. win7休眠开启与关闭
  16. 四元数AHRS姿态解算和IMU姿态解算分析
  17. vue3-vite-ts-vuex-element-plus
  18. qrc文件的使用方法
  19. 英文个人简历中英文词汇对照大全
  20. Doxygen 详细使用

热门文章

  1. 单细胞分析可视化工具盘点
  2. 网页集成支付宝扫码登录
  3. 面试题——二进制相关(最小白鼠试毒问题)
  4. 程序ajax请求公共组件app-jquery-http.js中url参数部分的项目应用
  5. 读论文:Charting the Right Manifold:Manifold Mixup for Few-shot Learning
  6. 国家省份城市级联菜单
  7. linux连接oracle的日志,linux shell脚本连接oracle查询数据插入文件和日志文件中
  8. 51Nod-1000A+B
  9. 新疆自治区谷歌地球高程DEM等高线下载
  10. 后门触发器之频域角度——Rethinking the Backdoor Attacks’ Triggers A Frequency Perspective