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

news/2025/1/20 6:11:46/

一、 背景

因为项目中需要使用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.2office-home: /opt/libreoffice24.2# 端口(线程)portNumbers: [8101,8102,8103]maxTasksPerProcess: 100# 任务执行的超时时间task-execution-timeout: 360000# 任务队列的超时时间task-queue-timeout: 360000# 一个进程的超时时间process-timeout: 360000

使用也很简单

    @Resourceprivate 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: trueurl: http://192.168.1.16:8100ssl: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 failedat 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 outat 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: trueoffice-home: D:\workplaces\libreofficeport-numbers: 9999load-document-mode: remotestart-fail-fast: truehost-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;" &

dockerlibreoffice_223">三、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没有中文乱码问题(之前有人上传了一些字体),所以服务器上我就没有上传字体,于是就出现了该问题,字体还是要上传全的。
问题就出在字体上,上传上去字体就好了


http://www.ppmy.cn/news/1564603.html

相关文章

Web3 数字资产如何更有趣?解锁 Ultiland 融合 MeMe 与 RWA 的技术路径

链上数字资产的快速发展&#xff0c;如何与艺术创作深度融合&#xff1f;一众实体资产渴望向 Web3 无缝跃迁&#xff0c;你知道 Ultiland 交出了一份怎样的答卷吗&#xff1f;创新 Meme-like RWA 模型&#xff0c;让艺术品、房地产等资产进入 Web3&#xff0c;开启全新投资体验…

PyTest自学-认识PyTest

1 PyTest自学-认识PyTest 1.1 PyTest可以用来做什么&#xff1f; PyTest是一个自动化测试框架&#xff0c;支持单元测试和功能测试&#xff0c;有丰富的插件&#xff0c;如&#xff0c;pytest-selemium, pytest-html等。 1.2 安装pytest 使用pip install -U pytest。 1.3 py…

Python爬虫学习前传 —— Python从安装到学会一站式服务

早上好啊&#xff0c;大佬们。我们的python基础内容的这一篇终于写好了&#xff0c;啪唧啪唧啪唧…… 说实话&#xff0c;这一篇确实写了很久&#xff0c;一方面是在忙其他几个专栏的内容&#xff0c;再加上生活学业上的事儿&#xff0c;确实精力有限&#xff0c;另一方面&…

如何使用wireshark 解密TLS-SSL报文

目录 前言 原理 操作 前言 现在网站都是https 或者 很多站点都支持 http2。这些站点为了保证数据的安全都通过TLS/SSL 加密过&#xff0c;用wireshark 并不能很好的去解析报文&#xff0c;我们就需要用wireshark去解密这些报文。我主要讲解下mac 在 chrome 怎么配置的&…

Visual Studio2019调试DLL

1、编写好DLL代码之后&#xff0c;对DLL项目的属性进行设置&#xff0c;选择待注入的DLL&#xff0c;如下图所示 2、生成DLL文件 3、将DLL设置为启动项目之后&#xff0c;按F5启动调试。弹出选择注入的exe的界面之后&#xff0c;使用代码注入器注入步骤2中生成的dll&#xff…

探秘Shortest与Stagehand:开启高效测试与自动化新篇

探秘Shortest与Stagehand&#xff1a;开启高效测试与自动化新篇 在数字化浪潮的推动下&#xff0c;网页自动化工具如同繁星般涌现&#xff0c;为众多行业带来了效率的变革。在这些工具中&#xff0c;Shortest和Stagehand凭借其出色的表现&#xff0c;成为了众多开发者、测试人…

大数据-263 实时数仓 - Canal 工作原理 工作流程 MySQL Binglog基本介绍

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; MyBatis 更新完毕目前开始更新 Spring&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; H…

C#异步多线程——浅谈async/await底层原理

async/await是块语法糖&#xff0c;编译器帮助我们做了很多工作&#xff0c;下面我们就简单剖析一下async/await的底层原理。 反编译工具ILSpy安装 我用的是ILSpy反编译生成的dll程序集。还没有ILSpy工具的小伙伴可以直接在VS中安装&#xff1b;点击Extensions>Manage Ext…