推荐使用官网原版镜像)

发布时间:2025-06-24 19:35:00  作者:北方职教升学中心  阅读量:274


中文文档:[https://api.onlyoffice.com/zh/editors/basic](https://api.onlyoffice.com/zh/editors/basic)

1. 搭建私有的OnlyOffice的服务

搭建过程这里就不进行涉猎了,建议使用docker进行搭建,下载官方镜像包即可,(现在dockerhub被墙,自行解决,不建议自己再次打包,因为我在尝试的时候总是出现莫名奇妙的问题可能是我的问题。推荐使用官网原版镜像)。app.js 是核心js文件

  1. only office 我只使用他的一个编辑的功能(这是一个核心,就是编辑文件,文件的来源和存储与它无关)
  2. 被编辑的文件从哪里获取?从 config 对象中的配置获取,这里就需要自行实现。

    @Operation(summary ="文件编辑之后的回调")@Parameters({@Parameter(name ="fileId",description ="文件的ID",in =ParameterIn.PATH)})@PostMapping("/edit/callback/{fileId}")publicvoideditCallBack(@PathVariableStringfileId,HttpServletRequestrequest,HttpServletResponseresponse){try{PrintWriterwriter =response.getWriter();Stringbody;try{Scannerscanner =newScanner(request.getInputStream());scanner.useDelimiter("\A");body =scanner.hasNext()?scanner.next():"";scanner.close();}catch(Exceptionex){writer.write("get request.getInputStream error:"+ex.getMessage());return;}if(body.isEmpty()){writer.write("empty request.getInputStream");return;}JSONObjectjsonObj =JSON.parseObject(body);intstatus =(Integer)jsonObj.get("status");log.debug("================文件编辑获取到的参数是:{}",JSON.toJSONString(jsonObj));intsaved =0;if(List.of(2,3,6).contains(status)){StringdownloadUri =(String)jsonObj.get("url");log.debug("================文件进行保存处理,需要保存的状态值是:{},可以获取到文件的路径是:{}",status,downloadUri);try{URLurl =newURL(downloadUri);// 根据文件下载地址来获取编辑后的文件流HttpURLConnectionconnection =(HttpURLConnection)url.openConnection();InputStreamstream =connection.getInputStream();if(stream ==null){thrownewException("Stream is null");}// TODO 根据文件的唯一标识获取数据库中文件记录EtmfFileInfofileInfo =fileInfoOpt.getById(fileId);// TODO 根据文件流创建一个文件FilesavedFile =newFile(fileInfo.getFileName());try(FileOutputStreamout =newFileOutputStream(savedFile)){intread;finalbyte[]bytes =newbyte[1024];while((read =stream.read(bytes))!=-1){out.write(bytes,0,read);}out.flush();}// TODO 根据文件上传到 MINIO中booleanb =smoMinIoUtils.uploadFile(fileInfo.getFileUrl(),savedFile);log.info("编辑文件后,文件上传状态:{},上传的文件是:{},Id是:{}",b,fileInfo.getFileName(),fileId);savedFile.delete();connection.disconnect();}catch(Exceptionex){saved =1;ex.printStackTrace();}finally{// 正常保存的时候剔除掉redis缓存if(status ==TWO){redisUtil.hdel(RedisName.ONLY_OFFICE_FILE_KYE,fileId);}}}writer.write("{"error":"+saved +"}");writer.flush();writer.close();log.debug("======================编辑完成--------------返回值是:{}","{"error":"+saved +"}");}catch(IOExceptione){e.printStackTrace();thrownewSmoGlobalException(CustomExceptionType.OTHER_ERROR);}}

    3. 总结

    文件的在线编辑主要就是依托与onlyoffice实现的,而编辑器的配置是通过我们的接口来定义的,接口中的配置可以自由的定义编辑器的文件类型,窗口大小,文件来源,回调地址,保存类型等等。

  3. 4.2 TOKEN是可以可选项,建议一开始不要使用,后面有需要的时候再去添加。
    文件编辑后的处理都是在回调中处理的,最好先看一下文档的回调写法。api比较全面,还有中文的文档。唯一遗憾的就是效率比较低,在使用私有对象存储的时候存在延迟。

2. SpringBoot进行交互

2.1 环境

java: 17
boot: 3.0.5
页面:一个h5页面即可
需要的其他依赖

<!-- ... 其他的依赖自行添加即可,不重要,比如 fastjson2,jackson 等 --><!-- 这个JAR 主要的作用是与OnlyOffice交互的时候生成token使用的 --><dependency><groupId>com.inversoft</groupId><artifactId>prime-jwt</artifactId><version>1.3.1</version></dependency>

2.2 我们的流程

我们使用一个 H5 页面即可,页面通过加载一个 app.js 。

然后通过一个 config 进行渲染,就可以实现一个编辑。
  • 4.3 一定要看一下官网文档,文档真的很全很重要
  • 4.4 协同的话只要参数就是一个KEY,如果需要超过20个的限制直接重新编译即可,大神一大堆,很容易就可以找到。所以提醒一下。

    SpringBoot整合OnlyOffice

    • SpringBoot整合OnlyOffice实现在线编辑
      • 1. 搭建私有的OnlyOffice的服务
      • 2. SpringBoot进行交互
        • 2.1 环境
        • 2.2 我们的流程
        • 2.3 接口规划
          • 2.3.1 获取编辑器配置的接口
          • 2.3.2 文件下载地址
          • 2.3.3 文件下载地址
      • 3. 总结
        • 4. 注意
          • 4.1 你的项目的地址一定一定要和onlyoffice可以正常通讯,如果不行则一直不可能成功。还有一点比较好的就是支持协同,并且支持协同,虽然协同在社区版中存在限制,但是支持代码修改,可以重新编译。其他的没有使用到,所以不进行评论。然后在对这个文件进行存储。回调的时候记得打印日志,观察一下接口的内容,一定要记得是通过回调中的url参数来获取编辑后的文件流的,并不是通过回调接口直接把文件流给到你。

            4. 注意

            4.1 你的项目的地址一定一定要和onlyoffice可以正常通讯,如果不行则一直不可能成功。
          • 2.3.1 获取编辑器配置的接口
            /** * 被编辑文件的下载连接 * 这里就是自己服务的配置地址 * only office 调用你的服务的地址,一定是 onlyoffice服务可以ping通的你的项目地址。

    SpringBoot整合OnlyOffice实现在线编辑

    公司有一个需求,就是实现 *Word* , *Excel* ,等文件的在线编辑,市场上面进行了多方面的选型,考虑了 *[OpenOffice](https://openoffice.apache.org/)* , *[Office Online](https://www.microsoft.com/zh-cn/microsoft-365/free-office-online-for-the-web?legRedir=true&CorrelationId=13c8a865-b9b0-48ff-b3ed-3ea9ec31cd55)*, 但是最终还是选择了 *[OnlyOffice](https://www.onlyoffice.com/zh/)* 这个产品。他的一个很大的优势在于开源,支持协同,社区比较活跃。社区的大佬很多,很赞。
    4.3 一定要看一下官网文档,文档真的很全很重要
    4.4 协同的话只要参数就是一个KEY,如果需要超过20个的限制直接重新编译即可,大神一大堆,很容易就可以找到。
    你需要编辑的文件可以放在任意的位置,只要你的接口可以通过流的方式给到onlyofiice编辑器即可。
  • 编辑后的文件如何获取?config对象中有一个回调地址,这个地址会给到服务器一个编辑的状态,并且携带一个获取编辑后文件的url(这个url就是only office 服务中的一个文件下载地址),根据这个url来获取编辑后的文件。但是开的成本就是你对接的时候需要获取token然后在进行交互。根据官方文档一步步操作即可。
    回调的实现参考:https://api.onlyoffice.com/zh/editors/callback#status
  • 在这里插入图片描述

    2.3 接口规划

    一共设计三个接口,

    1. 获取编辑器的配置
    2. 获取需要编辑的文件流
    3. 编辑后保存文件的回调
      保存后的文件:注意,这里编辑后的文件并不是在回调里面以流的形式给,而是在回调接口里面给服务器一个状态,根据状态去获取一个下载编辑后文件的一个地址,然后根据地址去主动的获取文件。
      4.2 TOKEN是可以可选项,建议一开始不要使用,后面有需要的时候再去添加。ping不通=白搭 */@Value("${only.office.downUrl}")privateStringdownFileUrl ="";/** * 这里是回调地址:例如 http://192.168.0.10:8080/office/edit/callback/{fileId} * 自行定义即可(就是后面自己编写的接口,但是一定要通可onlyoffice服务互通) * only office 调用你的服务的地址,一定是 onlyoffice服务可以ping通的你的项目地址。我在这里没有注意看饶了弯路。搭建过程中,如果是自己玩建议不要开启 **JWT** ,生产环境建议开一下。ping不通=白搭 */@Value("${only.office.callBackUrl}")privateStringeditCallBackUrl ="";@Operation(summary ="根据文件的ID来获取在线编辑的配置和token")@PostMapping("/token/{fileId}")@Parameters({@Parameter(name ="fileId",description ="不是对象ID是文件的ID",in =ParameterIn.PATH)})publicResultVo<?>getToken(@PathVariableStringfileId){StringfileKey ;if(redisUtil.hHasKey(RedisName.ONLY_OFFICE_FILE_KYE,fileId)){fileKey =redisUtil.hget(RedisName.ONLY_OFFICE_FILE_KYE,fileId).toString();//return ResultVo.error(CustomExceptionType.ONLY_OFFICE_COORDINATION_ERROR);}else{fileKey =fileId +RandomUtil.randomNumbers(10);}Stringjson =""" { "document": { "title": "%s", "key": "%s", "fileType":"%s", "lang": "zh-CN", "permissions": { "comment": true, "commentGroups": { "edit": ["Group2", "Group1"], "remove": [""], "view": "" }, "copy": true, "deleteCommentAuthorOnly": false, "download": true, "edit": true, "editCommentAuthorOnly": false, "fillForms": true, "modifyContentControl": true, "modifyFilter": true, "print": true, "review": true, "reviewGroups": ["Group1", "Group2", ""] }, "url": "%s" }, "editorConfig": { "customization":{ "autosave": true, "forcesave": true } "lang": "zh-CN", "callbackUrl": "%s", "onEditing": { "mode": "fast", "change": true }, "mode": "edit", "user": { "group": "Group1", "id": "%s", "name": "%s" } } } """;// TODO 这里文件的key可以通过redis进行保存,这样可以支持多人在线协同,现在不做处理json =String.format(json,fileInfo.getFileName(),fileKey,// TODO 这里是文件类型,自行定义'xlsx',// TODO 这里是文件下载地址,fileId 为文件的唯一标识,自行定义downFileUrl +fileId,// TODO 这里是定义回调地址,fileId 为文件的唯一标识用来区分是那个文件编辑的回调。editCallBackUrl +fileId,"userid","username");Map<String,Object>map =JSONObject.parseObject(json,newTypeToken<Map<String,Object>>(){}.getType());// TODO 这里是获取onlyoffice 交互的token,自己写的建议直接注释// String token = jwtManager.createToken(map);// map.put("token", token);// TODO 这个key可以直接注释,这里主要作用是协同redisUtil.hset(RedisName.ONLY_OFFICE_FILE_KYE,fileId,fileKey,60*60*24);returnResultVo.success(map);}
      2.3.2 文件下载地址

      这个接口的作用就是获取一个文件流,根据ID来获取一个文件流

      这里的地址就是上一个接口中下载文件的地址。

      @GetMapping("down/file/{fileId}")@Operation(summary ="根据参数下载一个文件")publicvoiddownFolderById(@PathVariableStringfileId,HttpServletResponseresponse){// TODO 1. 根据文件的唯一ID来获取数据库中的记录EtmfFileInfofileInfo =fileInfoOpt.getById(fileId);// TODO 2. 根据下载路径从 minio 中获取文件流 (因为我们使用的是minio,其他的自行切换即可)try(InputStreaminputStream =smoMinIoUtils.downloadFile(fileInfo.getFileUrl())){downFileInfo(response,fileInfo,inputStream);}catch(ServerException|ErrorResponseException|InsufficientDataException|IOException|NoSuchAlgorithmException|InvalidKeyException|InvalidResponseException|XmlParserException|InternalExceptione){JwtUtil.responseError(response,500L,"文件下载失败:"+e.getMessage());}}publicstaticvoiddownFileInfo(HttpServletResponseresponse,EtmfFileInfofileInfo,InputStreaminputStream)throwsIOException{response.setCharacterEncoding("UTF-8");response.setContentType("application/octet-stream; charset=UTF-8");response.addHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(fileInfo.getFileName(),StandardCharsets.UTF_8));ServletOutputStreamstream =response.getOutputStream();IOUtils.copy(inputStream,stream);stream.flush();stream.close();}
      2.3.3 文件下载地址

      这里是文件的回调地址,主要就是获取一个状态码,然后根据状态码判定是否保存文件。