news 2026/4/15 11:48:21

springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice

一、 背景

因为项目中需要使用word转pdf功能,因为转换速度原因,最后选用了libreoffice,原因及部署请参考
linux ubuntu环境安装libreoffice,word转pdf
远程调用的话可选docker部署,请看2.3.1

二、springboot整合libreoffice

其实springboot整合libreoffice有两种方式,一种是使用本地的libreoffice,一种是使用远程服务的libreoffice(这个好多文章中没有提到,也是自己踩的坑算是)

2.1、整合本地服务

引入pom

<dependency> <groupId>org.jodconverter</groupId> <artifactId>jodconverter-spring-boot-starter</artifactId> <version>4.4.2</version> </dependency> <dependency> <groupId>org.jodconverter</groupId> <artifactId>jodconverter-local</artifactId> <version>4.4.2</version> </dependency>

yml配置

jodconverter: local: enabled: true #window地址: D:\workplaces\jcxx\libreoffice 请自行补全 #linux地址: /opt/libreoffice24.2 office-home: /opt/libreoffice24.2 # 端口(线程) portNumbers: [8101,8102,8103] maxTasksPerProcess: 100 # 任务执行的超时时间 task-execution-timeout: 360000 # 任务队列的超时时间 task-queue-timeout: 360000 # 一个进程的超时时间 process-timeout: 360000

使用也很简单

@Resource private DocumentConverter documentConverter; public void test() { //流转换 documentConverter.convert(inputStream).as(DefaultDocumentFormatRegistry.DOCX).to(outStream).as(DefaultDocumentFormatRegistry.PDF).execute(); //文件转换,sourceFile和targetFile都是File类实例 documentConverter.convert(sourceFile).to(targetFile).as(DefaultDocumentFormatRegistry.PDF).execute(); }

2.2、整合远程服务

说一下怎么发现的,学过springboot的应该都知道,整合其他服务时候应该都有个配置类xxxAutoConfiguration

于是发现了除了一个local外,还有个remote,才发现可以直接调用远程服务,发现了那就可以整合使用,如下
pom引入

<dependency> <groupId>org.jodconverter</groupId> <artifactId>jodconverter-spring-boot-starter</artifactId> <version>4.4.2</version> </dependency> <dependency> <groupId>org.jodconverter</groupId> <artifactId>jodconverter-remote</artifactId> <version>4.4.2</version> </dependency>

yml配置

jodconverter: remote: enabled: true url: http://192.168.1.16:8100 ssl: enabled: false

注意,一定要加http,我就不小心忽略了这个东西,只写了个ip+端口,结果导致一致报错

java.net.MalformedURLException: no protocol

以下可不看,直接看踩坑
使用方式和local的一样,参考上面
不过比local方式多了一步,要手动启动远程的libreoffice服务
启动命令,附上对应命令的含义
https://help.libreoffice.org/latest/zh-CN/text/shared/guide/start_parameters.html

soffice --headless --nologo --nofirststartwizard --norestore --accept="socket,host=0.0.0.0,port=8100;urp;" &

以为到此就结束了吗?不不不,是我想的太简单了
对了,上面的命令还踩了一些坑,百度的时候都是127.0.0.1,想telnet通的的话需要使用0.0.0.0,不过,纠结这个似乎没啥意义,原因似乎不在这里(当时还花了好久排查)
不用0.0.0.0的话,直接报错连不上对应ip端口,改了之后报下面的错

2.3、整合远程服务踩坑

当我在服务器上运行该命令后,满心欢喜的等着转换完成时,突然转换就卡住了,随后报错

org.jodconverter.core.office.OfficeException: Remote conversion failed at org.jodconverter.remote.task.RemoteConversionTask.execute(RemoteConversionTask.java:162) at org.jodconverter.remote.office.RemoteOfficeManagerPoolEntry.doExecute(RemoteOfficeManagerPoolEntry.java:301) at org.jodconverter.core.office.AbstractOfficeManagerPoolEntry.lambda$execute$0(AbstractOfficeManagerPoolEntry.java:80) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(SocketInputStream.java) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137) at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153) at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56) at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259) at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163) at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:157) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273) at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) at org.apache.http.client.fluent.Request.internalExecute(Request.java:173) at org.apache.http.client.fluent.Executor.execute(Executor.java:262) at org.jodconverter.remote.task.RemoteConversionTask.execute(RemoteConversionTask.java:147) ... 6 more

连接超时?我telnet一下,端口通啊!最最让我恶心的是,我上周快下班时候使用这种方式成功转换了一次,这就给我一种错觉,可能是我启动命令的问题,于是就疯狂尝试修改启动命令,找对应的参数。结果都没卵用。。。。。。于是想上周是不是搞错了,让我误以为这样可行?
结果还真是,命令行启动压根就不能使用remote。不过没找到上周为啥成功的原因?也忘了上周咋成功的了。。。
https://github.com/jodconverter/jodconverter/wiki/LibreOffice-Remote

看到这我就懵了,我还得去安装个Collabora Online 或者LibreOffice Online?(当前,这也是可行的)。我看了下这两东西基本就是属于web端的在线编辑word了。。。
于是又开始找,不过这回学聪明了点,只在github中的issues中找,搜索关键词remote
还真让我找出来两种办法:但是我只成功了一种
对了,扔几个issues链接,有兴趣的可以看下

https://github.com/jodconverter/jodconverter/wiki/Migration-Guide-4.4.5 https://github.com/jodconverter/jodconverter/issues/40 https://github.com/jodconverter/jodconverter/issues/350 https://github.com/jodconverter/jodconverter/issues/397
2.3.1、方法一(成功)

也就是https://github.com/jodconverter/jodconverter/issues/397这个里面提到的方案。代码很简单,都可以看下,简单来说就是本地启动一个libreoffice服务,并对外提供接口调用(就一个controller)
docker镜像拉不下来参考这个,我是看第一点成功的https://blog.csdn.net/weixin_50160384/article/details/139861337
jodconverter提供了一个远程服务的接口,我们可以直接docker运行

docker run -d -p 8100:8100 --privileged=true -v /usr/share/fonts:/usr/share/fonts -v /opt/application.properties:/etc/app/application.properties ghcr.io/jodconverter/jodconverter-examples:rest

挂载对应字体,否则中文不显示
-v /usr/share/fonts:/usr/share/fonts
挂载配置文件,用于修改端口等
-v /opt/application.properties:/etc/app/application.properties
配置文件在这看https://github.com/jodconverter/docker-image-jodconverter-examples
对应文件我也贴下

# amount of libreOffice instances to start - one for each given port. So this means 2 jodconverter.local.port-numbers: 2002, 2003 # change the tmp folder jodconverter.local.working-dir: /tmp # change upload sizes spring.servlet.multipart.max-file-size: 5MB spring.servlet.multipart.max-request-size: 5MB # change the server port (where the REST app is listenting server.port=8100

然后这个的ip+端口号使用jodconverter.remote方式就成功了
也许有同学已经安装好了libreoffice,想着我这libreoffice不白装了,最后用docker。。。
其实也不然,可以自己将项目打个包放到服务器去运行,不过这个需要自己研究下了
https://github.com/jodconverter/jodconverter-samples
不过我看了下dockerfile文件,可能是这个命令(没用过gradlew )

2.3.2、使用local参数,但是使用远程服务器(失败)

根据https://github.com/jodconverter/jodconverter/wiki/Migration-Guide-4.4.5描述及https://github.com/jodconverter/jodconverter/issues/40,似乎可以使用local来进行访问
于是,有了如下配置

jodconverter: local: enabled: true office-home: D:\workplaces\libreoffice port-numbers: 9999 load-document-mode: remote start-fail-fast: true host-name: 120.46.141.243

有一点很让人费解,使用了remote模式,还必须配置office-home。。。我使用远程服务上的地址还不行。。。还有一点,必须要提前启动位于服务器上的9999端口服务,不提前启动程序启动不起来。
然后我尝试了下,虽然也能转换成功,但是用了40多秒。
不清楚是什么原因,解决的小伙伴可以在评论区讨论下

soffice --headless --nologo --nofirststartwizard --norestore --accept="socket,host=0.0.0.0,port=9999;urp;" &

三、docker中同时部署应用和libreoffice(不推荐)

单独部署libreoffice的可以自己再查询下,这里就不介绍了
因为一开始我只发现了local这种方式,所以就在window本地和linux服务器上都部署了下,后来突然想到,丫的服务是用的docker进行部署的。docker里面又没有libreoffice,还访问个屁呀,我linux部署上没啥用啊!
意识到这点后,首先尝试着把Linux中的libreoffice挂载到docker容器中,但以交互模式进去后
soffice还是libreoffice24.2都执行不了。。。。
那想着只能将libreoffice也弄到容器中去了。。。
于是有了下面的dockerfile文件

# 使用基于 Alpine 的 OpenJDK 镜像 FROM registry.cn-beijing.aliyuncs.com/hub-mirrors/openjdk:8-jdk-alpine # 更新包列表并安装必要的软件 RUN apk add --no-cache bash libreoffice # 复制 jar 文件到容器 COPY xxx.jar app.jar COPY fonts/zhFonts /usr/share/fonts # 设置环境变量 ENV JAVA_HOME=/usr/lib/jvm/default-jvm ENV LIBREOFFICE_HOME=/usr/lib/libreoffice ENV PATH=$JAVA_HOME/bin:$LIBREOFFICE_HOME/program:$PATH # 设置 ENTRYPOINT 以允许使用 exec ENTRYPOINT ["/bin/bash", "-c"] # 设置 CMD 以启动 Java 应用 CMD ["java -Djava.security.egd=file:/dev/./urandom -jar app.jar"] #LibreOffice 6.1.4.2 版本

也许对docker还是不太熟悉,在copy命令的时候源文件似乎不能使用绝对路径,这个让我有点奇怪,
于是把东西全都挪到了/opt目录下

然后执行命令,注意最后有个.

docker build -t新镜像名字:TAG.

不推荐的原因就是在于此,一个镜像高达1g。。。
实测后libreoffice和服务都是正常的,可以接受镜像大和构建时间长些的也可以使用这种方式

发现这点后,我感觉这也太low了,毕竟之前jar包也就将近200m,而且使用的是阿里的云效流水线构建工具,这样构建一次得花多久?(没有去公司服务器尝试,自己用云服务器尝试,第一次构建dockerfile拉取libreoffice花了得10多分钟,第二次用dockerfile构建就是秒拉取了,可能也只是第一次慢?不知道用云效如何?有兴趣的可以尝试下)。
尝试着找别的方法解决,于是无意中发现了JodConverterRemoteAutoConfiguration,对应配置类
JodConverterRemoteProperties

四、其他问题

4.1、使用远程的libreoffice时候用excel转pdf的时候样式错乱

本来是这样的格式

变成了这样

反正发现这个问题我是很懵圈的。但没办法,排查呗。
尝试下本地的libreoffice另存为是正常的。
尝试下代码本地的libreoffice也是正常的。
尝试下inux的本地的libreoffice也是正常的。
然后我就开始怀疑是不是remote源码层面的问题,于是去把remote的代码弄到本地试了下,也是正常的。
然后我就想着用自己买的服务器试试,是不是application配置文件的问题,但是,我发现,我自己服务器的远程服务是正常的
那我就意识到了,都是docker容器,不一样的只能是挂载文件,那问题就只能出在字体上了,因为用服务器试过word转pdf没有中文乱码问题(之前有人上传了一些字体),所以服务器上我就没有上传字体,于是就出现了该问题,字体还是要上传全的。
问题就出在字体上,上传上去字体就好了

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/14 22:25:47

DLSS Swapper终极教程:3分钟学会游戏画质升级技巧

DLSS Swapper终极教程&#xff1a;3分钟学会游戏画质升级技巧 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 还在为游戏画面模糊、帧率不稳而烦恼吗&#xff1f;DLSS Swapper让你无需更换硬件就能获得显著的画质提升&…

作者头像 李华
网站建设 2026/4/15 11:46:56

GHelper性能优化终极指南:3步解锁华硕笔记本隐藏性能

GHelper性能优化终极指南&#xff1a;3步解锁华硕笔记本隐藏性能 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops. Control tool for ROG Zephyrus G14, G15, G16, M16, Flow X13, Flow X16, TUF, Strix, Scar and other models 项目地址…

作者头像 李华
网站建设 2026/4/15 11:46:55

PDF-Extract-Kit公式识别教程:图片转LaTeX代码详解

PDF-Extract-Kit公式识别教程&#xff1a;图片转LaTeX代码详解 1. 引言 在学术研究、论文撰写和技术文档编写中&#xff0c;数学公式的数字化处理是一项高频且繁琐的任务。传统方式依赖手动输入 LaTeX 公式&#xff0c;效率低且容易出错。PDF-Extract-Kit 是一个由“科哥”二…

作者头像 李华
网站建设 2026/3/29 15:09:49

DLSS版本管理神器:DLSS Swapper全面实战指南

DLSS版本管理神器&#xff1a;DLSS Swapper全面实战指南 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 在当今游戏技术快速迭代的时代&#xff0c;DLSS版本兼容性问题成为许多玩家的困扰。DLSS Swapper作为专业的DLSS…

作者头像 李华
网站建设 2026/4/11 22:49:10

Blender3mf插件:3D打印模型处理的终极解决方案

Blender3mf插件&#xff1a;3D打印模型处理的终极解决方案 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat Blender3mf插件为3D打印工作流程带来了革命性的便利&#xff0…

作者头像 李华
网站建设 2026/4/12 17:03:42

时间轮算法

✅什么是时间轮&#xff1f; 视频理解&#xff1a;时间轮算法 典型回答 时间轮算法&#xff08;Time Wheel Algorithm&#xff09;是一种用于处理定时任务和调度的常见算法。 时间轮算法主要需要定义一个时间轮盘&#xff0c;在一个时间轮盘中划分出多个槽位&#xff0c;每…

作者头像 李华