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.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)
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;" &
三、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
相关文章:
springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice
一、 背景 因为项目中需要使用word转pdf功能,因为转换速度原因,最后选用了libreoffice,原因及部署请参考 linux ubuntu环境安装libreoffice,word转pdf 远程调用的话可选docker部署,请看2.3.1 二、springboot整合libr…...
从入门到精通:大学生编程技能提升全攻略
文章目录 每日一句正能量前言编程语言选择编程语言选择:为新手导航Python:初学者的友好伙伴JavaScript:Web开发的核心Java:企业级应用的经典C:系统编程的基石Ruby:优雅高效的编程Swift:iOS开发的…...
C# .NET Framework的特殊委托
C# .NET Framework的特殊委托 .NET Framework中定义了几种特殊的委托类型,以简化委托的使用。以下是一些常用的特殊委托类型: Predicate<T> 这是一个返回布尔值的委托,接受一个类型为T的参数。常用于定义过滤条件。 using System; …...
C# 判断电脑是否联网
项目中连接webAPI需要判断是否联网,故找到这个方法,不需要引用任何dll,代码复制一下,直接使用。wininet.dll是系统自带的 public void Initial(){try{ if (IsNetworkConnected){SvMaster.Log.WriteInfo("网络…...
爬虫解析代码结构
在设计中加入一个顶层接口是有益的,特别是当您希望实现统一的接口来处理所有类型的排行榜数据时。这样做可以提供更好的灵活性和扩展性,同时保持代码的整洁和易于维护。 设计概述 接口: 定义一个 RankingDataCollector 接口,它定义了所有数…...
day 23 进程间通信—管道
注意事项: 1、如果管道中至少有一个写端: 如果管道中有数据,直接读出 如果管道中没有数据,会阻塞等待直到有数据写入后读出 2、如果管道中没有写端: 如果管道中有数据,直接…...
Python酷库之旅-第三方库Pandas(073)
目录 一、用法精讲 296、pandas.Series.dt.as_unit方法 296-1、语法 296-2、参数 296-3、功能 296-4、返回值 296-5、说明 296-6、用法 296-6-1、数据准备 296-6-2、代码示例 296-6-3、结果输出 297、pandas.Series.dt.days属性 297-1、语法 297-2、参数 297-3、…...
使用easyexcel导出,发生了Exception: could not find acceptable repesentation
报错信息: 原因以及解决方案: 原因是我的代码使用Resp响应返回实体,其实使用EasyExcel导出已经设置了响应编码,导致重复了。 当你通过 HttpServletResponse 的输出流写入文件时,你已经直接控制了响应体。如果此时还尝…...
android display 笔记(五)HWC(Hardware Composer)
HWC 简单来说HWC是用来合成图形和显示图形的,可以把多个图形缓存传给硬件混合渲染器,让硬件混合渲染器执行合成操作,显示图形就是直接将图形缓存显示到屏幕。 android 14 /hardware/interfaces/graphics/composer/2.1/IComposer.hal 19 im…...
【模电笔记】——集成运算放大电路
tips:本章节的笔记已经打包到word文档里啦,建议大家下载文章顶部资源(有时看不到是在审核中,等等就能下载了。手机端下载后里面的插图可能会乱,建议电脑下载,兼容性更好且易于观看),…...
Android Studio Gradle多渠道打包
原理使用Android Studio打一次渠道包,用反编译工具反编译后,修改渠道信息重新编译 准备文件 分渠道配置文件:channel.txt ↓ # 多渠道配置里“统计平台”、“市场名称”、“渠道编号”分别代表什么意思? # 统计平台:…...
什么是DNS缓存?DNS缓存有哪些作用和危害?
在互联网世界的运转机制中,DNS(域名系统)是其中的关键,而DNS缓存则是这一系统的重要环节。它既能加快网站的访问速度,同时也会对网络安全造成影响,因此了解DNS缓存对于网站的日常管理至关重要。 什么是DNS…...
web基础与http协议与配置
目录 一、web基础 1.1 DNS与域名(详解看前面章节) 1.2 网页的概念(HTTP/HTTPS) 1.2.1 基本概念 1.2.2 HTML文档结构(了解) 1.2.3 web相关重点 1.2.4 静态资源和动态资源 二、http协议 2.1 概述 2.2 cookie和session&…...
机械学习—零基础学习日志(python编程2)
零基础为了学人工智能,正在艰苦的学习 这里把,函数以及类相关的知识做一个笔记,放在这里。 期待与大家交流~ 变量作用域 Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的…...
element-plus的表单输入框有清除按钮的,文字输入前后宽度不一致怎么解决
输入内容之后多了一个可清除的图标,输入框的宽度也被撑开了 根据输入前后的dom对比发现,多了一个图标的span标签 :deep(.el-input__wrapper) {position: relative;.el-input__inner {padding-right: 18px;}.el-input__suffix {position: absolute;right:…...
解决Docker拉取镜像时 i/o timeout错误
目录 一,设置Docker镜像源(推荐) 1.1 解决方案1:配置加速地址 1.2 解决方案2:使用代理拉取镜像 1.3 解决方案3:备用办法:直接传送镜像 二,目前可用的镜像源 一,设置…...
面壁的智能开源 MiniCPM-V 2.6 边缘人工智能多模态功能与 GPT-4V 不相上下
"MiniCPM-V2.6 "是一个边缘多模态人工智能模型,仅拥有 80 亿个参数,却在单图像、多图像和视频理解任务中取得了低于 200 亿个参数的三项 SOTA(艺术境界)成绩,显著增强了边缘多模态能力,并与 GPT-…...
dhcp+checkkickstar的实验理解
文章目录 实验介绍使用的服务介绍PXE服务dhcp服务Kickstart 服务tftp服务 第一部分(基础部分)代码展示注意点第一点第二点 结果展示 第二部分(…...
Android网络安全:如何防止中间人攻击
文章目录 引言一、中间人攻击概述二、预防中间人攻击的方法2.1 使用HTTPS2.2 证书锁定(Certificate Pinning)2.3 使用SSL/TLS最佳实践2.4 验证主机名 三、总结 引言 中间人攻击(Man-in-the-Middle,简称MITM)是一种常见…...
NOI Linux 2.0 的安装说明以及使用指南
关于 NOI Linux 2.0 NOI Linux 是 NOI 竞赛委员会基于 Ubuntu 操作系统开发的一款 Linux 桌面发行版,是一套免费的、专门为信息学奥林匹克竞赛选手设计的操作系统,是 NOI 系列赛事指定操作系统,适用于常见笔记本电脑和桌面电脑。 新建虚拟机…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
