当前位置: 首页 > article >正文

libreoffice容器word转pdf

先说结论,市面上不花钱的,简单的效果好的就是这个种方式,在线测试下来不如命令转的效果好。AsposeWords和SpireDoc效果都不错,但是只有这个word转pdf感觉花3-5w不划算。
下载容器路径 https://docker.aityp.com/i/search?search=libreoffice
部署LibreOffice容器
使用Docker运行LibreOffice的无头模式(headless),提供文档转换服务:

#需要挂载输入输出路径和安装字体路径
docker run -d \
--name libreoffice1 \
-v /opt/libreoffice1/input:/app/input \
-v /opt/libreoffice1/output:/app/output \
-v /usr/share/fonts/:/usr/share/fonts/
-p 3000:3000 \
linuxserver/libreoffice:latest #online用的是 需要注意容器配置文件有个位置需要改成一下 要不然http访问不通docker run -t -d -p 9980:9980 -e "username=admin" -e "password=123456" --restart always --cap-add SYS_ADMIN libreofficeonline:telecom

此命令启动一个LibreOffice容器,监听8100端口,并将宿主机目录挂载到容器内以便文件交换。

Java调用REST API转换文档
若容器提供REST API(如libreserver/office-api),可通过Java的HTTP客户端发送请求:

package cn.zjtele.pubinfo.demo.api.controller;import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.MDC;import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;import static com.sun.javafx.runtime.async.BackgroundExecutor.getExecutor;public class LibreOfficeOnlineMasterConverter {// 正确的API端点路径(根据您的服务器配置可能需要调整)private static final String LOOL_CONVERT_URL = "http://localhost:9980/lool/convert-to/pdf";// 如果需要忽略SSL证书验证static SSLContext sslContext;static {try {sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build();} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);} catch (KeyManagementException e) {throw new RuntimeException(e);} catch (KeyStoreException e) {throw new RuntimeException(e);}}// 在类初始化时创建共享的HttpClientprivate static final CloseableHttpClient sharedHttpClient = HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setMaxConnTotal(100)  // 最大连接数.setMaxConnPerRoute(20) // 每个路由最大连接数.build();public static void printPoolStatus() {ThreadPoolExecutor executor = (ThreadPoolExecutor) getExecutor();System.out.println("活跃线程: " + executor.getActiveCount() +" / 队列任务: " + executor.getQueue().size());}public static boolean convertToPdf(String inputFile, String outputFile) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {MDC.put("traceId", UUID.randomUUID().toString().substring(0,8));System.out.println("开始处理文件: " + inputFile);// 如果需要忽略SSL证书验证
//        SSLContext sslContext = SSLContexts.custom()
//                .loadTrustMaterial((chain, authType) -> true)
//                .build();// 修改convertToPdf方法中的httpClient获取方式
//        CloseableHttpClient httpClient = sharedHttpClient;// 调整HttpClient配置,增加超时控制RequestConfig config = RequestConfig.custom().setConnectTimeout(5000)       // 连接超时5秒.setSocketTimeout(30000)       // 数据传输超时30秒.build();CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(config).setConnectionManager(new PoolingHttpClientConnectionManager()) // 使用连接池.build();try {// 1. 创建POST请求HttpPost httpPost = new HttpPost(LOOL_CONVERT_URL);// 2. 构建Multipart请求体(尝试不同字段名)MultipartEntityBuilder builder = MultipartEntityBuilder.create();builder.addBinaryBody("file",  // 先尝试"file",如果失败再尝试"data"new File(inputFile),getContentType(inputFile),new File(inputFile).getName());// 3. 设置必要的头信息(master分支特定头)httpPost.setHeader("X-WOPI-Override", "CONVERT_TO");httpPost.setHeader("X-WOPI-FileExtension", getFileExtension(inputFile));httpPost.setHeader("X-WOPI-SuggestedTarget", getOutputFilename(outputFile));httpPost.setHeader("X-LOOL-WOPI-ConvertTo", "pdf");  // master分支特有httpPost.setHeader("Accept", "application/pdf");// 4. 添加其他可能的必要头httpPost.setHeader("User-Agent", "Java LibreOffice Converter");httpPost.setHeader("Cache-Control", "no-cache");httpPost.setEntity(builder.build());System.out.println("发送请求到: " + LOOL_CONVERT_URL);System.out.println("使用头信息: " + httpPost.getAllHeaders());// 5. 执行请求try (CloseableHttpResponse response = httpClient.execute(httpPost)) {int statusCode = response.getStatusLine().getStatusCode();HttpEntity entity = response.getEntity();System.out.println("响应状态: " + response.getStatusLine());System.out.println("响应头: " + response.getAllHeaders());if (statusCode == 200 && entity != null) {try (FileOutputStream fos = new FileOutputStream(outputFile)) {entity.writeTo(fos);}return true;} else {String responseBody = entity != null ?EntityUtils.toString(entity, StandardCharsets.UTF_8) : "无响应体";System.err.println("转换失败. 状态码: " + statusCode);System.err.println("响应体: " + responseBody);// 如果400错误,尝试使用"data"作为字段名if (statusCode == 400) {System.out.println("尝试使用'data'作为字段名重试...");return retryWithDataField(inputFile, outputFile);}}}} catch (Exception e) {System.err.println("转换过程中发生错误: " + e.getMessage());e.printStackTrace();} finally {try {httpClient.close();} catch (Exception e) {System.err.println("关闭HTTP客户端时出错: " + e.getMessage());}}return false;}/*** 使用"data"作为字段名重试*/private static boolean retryWithDataField(String inputFile, String outputFile) {CloseableHttpClient httpClient = HttpClients.createDefault();try {HttpPost httpPost = new HttpPost(LOOL_CONVERT_URL);MultipartEntityBuilder builder = MultipartEntityBuilder.create();builder.addBinaryBody("data",  // 使用"data"作为字段名new File(inputFile),getContentType(inputFile),new File(inputFile).getName());// 设置相同的头信息httpPost.setHeader("X-WOPI-Override", "CONVERT_TO");httpPost.setHeader("X-WOPI-FileExtension", getFileExtension(inputFile));httpPost.setHeader("X-WOPI-SuggestedTarget", getOutputFilename(outputFile));httpPost.setHeader("X-LOOL-WOPI-ConvertTo", "pdf");httpPost.setHeader("Accept", "application/pdf");httpPost.setEntity(builder.build());try (CloseableHttpResponse response = httpClient.execute(httpPost)) {if (response.getStatusLine().getStatusCode() == 200) {try (FileOutputStream fos = new FileOutputStream(outputFile)) {response.getEntity().writeTo(fos);}return true;}}} catch (Exception e) {System.err.println("重试失败: " + e.getMessage());}return false;}// 新增异步转换方法public static Future<Boolean> convertToPdfAsync(String inputFile, String outputFile) {return ConverterThreadPool.getExecutor().submit(() -> {try {return convertToPdf(inputFile, outputFile);} catch (Exception e) {System.err.println("异步任务执行异常: " + e.getMessage());return false;}});}// 新增批量处理方法public static Map<String, Future<Boolean>> batchConvert(Map<String, String> filePairs) {Map<String, Future<Boolean>> results = new ConcurrentHashMap<>();filePairs.forEach((input, output) ->results.put(input, convertToPdfAsync(input, output)));return results;}/*** 获取正确的内容类型*/private static ContentType getContentType(String filePath) {String ext = getFileExtension(filePath).toLowerCase();switch (ext) {case "docx": return ContentType.create("application/vnd.openxmlformats-officedocument.wordprocessingml.document");case "doc": return ContentType.create("application/msword");case "odt": return ContentType.create("application/vnd.oasis.opendocument.text");default: return ContentType.APPLICATION_OCTET_STREAM;}}private static String getFileExtension(String filePath) {int lastDotIndex = filePath.lastIndexOf('.');return lastDotIndex > 0 ? filePath.substring(lastDotIndex + 1) : "";}private static String getOutputFilename(String filePath) {return new File(filePath).getName();}public static void main(String[] args) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {String inputFile = "C:\\Users\\sheng\\Desktop\\chongqing.docx";String outputFile = "C:\\Users\\sheng\\Desktop\\chongqing.pdf";System.out.println("开始转换: " + inputFile + " → " + outputFile);boolean b = convertToPdf(inputFile, outputFile);System.out.println("转换结果: " + b);}
}

通过命令行调用容器内工具
若容器仅包含LibreOffice命令行工具,可通过Java执行Docker命令完成转换:

package cn.zjtele.pubinfo.demo.wordtopdf;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;public class LibreOfficeConverter {private static final String INPUT_DIR = "D:/docker/input";  // 本地输入目录private static final String OUTPUT_DIR = "D:/docker/output"; // 本地输出目录public static void main(String[] args) {
//        if (args.length == 0) {
//            System.out.println("请提供要转换的Word文件名(例如:example.docx)");
//            return;
//        }long l = System.currentTimeMillis();String fileName = "11.docx";Path inputFilePath = Paths.get(INPUT_DIR, fileName);File inputFile = inputFilePath.toFile();if (!inputFile.exists()) {System.out.println("文件不存在:" + inputFilePath);return;}try {// 确保输出目录存在Files.createDirectories(Paths.get(OUTPUT_DIR));// 构造输出文件路径String outputFileName = fileName.replace(".docx", ".pdf");Path outputFilePath = Paths.get(OUTPUT_DIR, outputFileName);// 调用 LibreOffice 容器进行转换convertFileUsingLibreOffice(inputFile.getAbsolutePath(), outputFilePath.toString());System.out.println("文件转换成功!PDF文件已保存到:" + outputFilePath);System.out.println("转换耗时:" + (System.currentTimeMillis() - l) + "ms");} catch (Exception e) {e.printStackTrace();System.out.println("文件转换失败!");}}private static void convertFileUsingLibreOffice(String inputFilePath, String outputFilePath) throws IOException, InterruptedException {// 使用 LibreOffice 容器命令进行转换String command = String.format(
//                "docker exec -i another_linuxserver-libreoffice libreoffice --headless --convert-to pdf --outdir /app/output /app/input/%s",
//                new File(inputFilePath).getName()"docker exec -i libreoffice767 libreoffice --headless --convert-to pdf --outdir /app/output /app/input/%s",new File(inputFilePath).getName());Process process = Runtime.getRuntime().exec(command);int exitCode = process.waitFor();if (exitCode != 0) {throw new RuntimeException("LibreOffice 转换失败,退出码:" + exitCode);}}
}

文件路径处理注意事项
确保Java应用有权限访问宿主机和容器的挂载目录。
输入/输出路径需使用容器内的映射路径(如/opt/documents)。
转换完成后从挂载目录提取PDF文件。

相关文章:

libreoffice容器word转pdf

先说结论&#xff0c;市面上不花钱的&#xff0c;简单的效果好的就是这个种方式&#xff0c;在线测试下来不如命令转的效果好。AsposeWords和SpireDoc效果都不错&#xff0c;但是只有这个word转pdf感觉花3-5w不划算。 下载容器路径 https://docker.aityp.com/i/search?searchl…...

AI模型升级与机器人产业落地同步推进

2025年5月28日&#xff0c;中国AI领域迎来两项实质性进展。DeepSeek-R1模型完成小版本试升级&#xff0c;开源社区发布其0528版本。本次更新聚焦语义理解精准性、复杂逻辑推理和长文本处理能力的提升。在代码测试平台Live CodeBench中&#xff0c;开发者反馈其编程性能已接近Op…...

安全编码与AI接口权限控制

安全编码与AI接口权限控制 在AI系统中,模型服务的开放接口往往涉及敏感数据、核心算法与算力资源,如果缺乏有效的安全编码与权限控制机制,极易引发数据泄露、滥用调用或非法操作等问题。本节将从“接口安全策略”“权限验证流程”“Token管控机制”“多租户身份隔离”四个方…...

linux centos 服务器性能排查 vmstat、top等常用指令

背景:项目上经常出现系统运行缓慢,由于数据库服务器是linux服务器,记录下linux服务器性能排查常用指令 vmstat vmstat介绍 vmstat 命令报告关于内核线程、虚拟内存、磁盘、陷阱和 CPU 活动的统计信息。由 vmstat 命令生成的报告可以用于平衡系统负载活动。系统范围内的这…...

MySQL----视图的创造和使用

这里写目录标题 **创造视图****查看视图****修改视图****更新视图****删除视图** 创造视图 使用create view…创造 语法格式 create[algorithm {undefiend&#xff5c;merge&#xff5c;temptable}]view <视图名> [(<字段名1>[,……,字段名n])]as <select 语…...

c/c++的opencv伽马噪声

理解与实现 C/OpenCV 中的伽马噪声 &#x1f5bc;️ 噪声是大多数图像采集过程中固有的组成部分。理解和模拟不同类型的噪声对于开发鲁棒的图像处理算法至关重要&#xff0c;尤其是在去噪方面。虽然高斯噪声和椒盐噪声是常被讨论的类型&#xff0c;但伽马噪声&#xff08;通常…...

LiveGBS国标视频平台收流模式:UDP、TCP被动与TCP主动传输模式之差异剖析

LiveGBS国标视频平台收流模式&#xff1a;UDP、TCP被动与TCP主动传输模式之差异剖析 1、背景2、信令传输3、视频流传输3.1、UDP传输模式3.2、TCP被动传输模式3.3、TCP主动传输模式 4、WEB配置流传输模式4.1、编辑模式4.2、下拉切换模式 5、搭建GB28181视频直播平台 1、背景 在…...

跳表(Skip List)查找算法详解

1、原理 跳表是一种概率型数据结构&#xff0c;通过多层有序链表实现高效查找&#xff0c;时间复杂度接近平衡树&#xff08;O(log n)&#xff09;。其核心思想是通过层级索引加速搜索&#xff0c;结构类似火车时刻表的“快车-慢车”模式。 关键特性&#xff1a; 多层链表&a…...

React从基础入门到高级实战:React 核心技术 - React 与 TypeScript:构建类型安全的应用

React 与 TypeScript&#xff1a;构建类型安全的应用 在现代前端开发中&#xff0c;TypeScript 因其强大的类型系统和编译时错误检查功能&#xff0c;已成为 React 开发者的热门选择。通过为代码添加类型定义&#xff0c;TypeScript 能够显著提升代码的健壮性、可维护性和团队…...

Django orm详解--组成部件

Django ORM 的核心部件可分为模型系统、查询系统、数据库后端和辅助工具四大类&#xff0c;每个部件负责不同的职责&#xff0c;共同实现对象与关系数据库的映射。以下是核心部件的分层解析&#xff1a; 一、模型系统&#xff08;Model System&#xff09; 1. 模型基类&#…...

Tomcat 使用与配置全解

一、 Tomcat简介 Tomcat服务器是Apache的一个开源免费的Web容器。它实现了JavaEE平台下部分技术规范&#xff0c;属于轻量级应用服务器。 1. Tomcat版本 Tomcat版本 JDK版本 Servlet版本 JSP版本 10.0.X 8 and later 5.0 3.0 9.0.x 8 and later 4.0 2.3 8.0.x 7…...

Chrome 开发中的任务调度与线程模型实战指南

内容 概述 快速入门指南 核心概念线程词典 线程任务优先使用序列而不是物理线程 发布并行任务 直接发布到线程池通过 TaskRunner 发布 发布顺序任务 发布到新序列发布到当前&#xff08;虚拟&#xff09;主题 使用序列代替锁将多个任务发布到同一线程 发布到浏览器进程中的主线…...

aws instance store 的恢复

1: aws instance store 要在launch instance 才可以创建,而且,通过snapshot 恢复后,instance store 里面的数据会丢失。 下面是创建instance store 的过程,和通过两种方式恢复,发现/etc/fstab 不同的写法,有的不能启动: [root@ip-xx ~]# lsblk NAME MAJ:MIN RM …...

从零开始创建 Vue 3 开发环境并构建第一个 Demo

Vue 3 是目前前端开发中非常流行的渐进式 JavaScript 框架。本文将手把手带你完成从环境搭建到运行一个基础 Vue 3 示例的全过程。 &#x1f4e6; 一、环境准备 1. 安装 Node.js Vue 项目依赖 Node.js 运行环境&#xff0c;请确保你的电脑已安装 Node.js&#xff08;建议使用…...

EasyRTC音视频实时通话助力微信小程序:打造低延迟、高可靠的VoIP端到端呼叫解决方案

一、方案概述​ 在数字化通信浪潮下&#xff0c;端到端实时音视频能力成为刚需。依托庞大用户生态的微信小程序&#xff0c;是实现此类功能的优质载体。基于WebRTC的EasyRTC音视频SDK&#xff0c;为小程序VoIP呼叫提供轻量化解决方案&#xff0c;通过技术优化实现低延迟通信&a…...

STM32 SPI通信(软件)

一、SPI简介 SPI&#xff08;Serial Peripheral Interface&#xff09;是由Motorola公司开发的一种通用数据总线四根通信线&#xff1a;SCK&#xff08;Serial Clock&#xff09;、MOSI&#xff08;Master Output Slave Input&#xff09;、MISO&#xff08;Master Input Slav…...

每日刷题c++

快速幂 #include <iostream> using namespace std; #define int long long int power(int a, int b, int p) {int ans 1;while (b){if (b % 2){ans * a;ans % p; // 随时取模}a * a;a % p; // 随时取模b / 2;}return ans; } signed main() {int a, b, p;cin >> a …...

(自用)Java学习-5.19(地址管理,三级联动,预支付)

1. 地址管理模块 地址展示 前端&#xff1a;通过 showAddress() 发起 Ajax GET 请求&#xff0c;动态渲染地址列表表格&#xff0c;使用 #{tag}、#{name} 等占位符替换真实数据。 后端&#xff1a; 控制器层调用 AddressService&#xff0c;通过 AddressMapper 查询用户地址数…...

【容器】docker使用问题处理

问题一、systemctl start docker启动报 ERROR: ZONE_CONFLICT: docker0 already bound to a zone 处理方法 firewall-cmd --permanent --zonedocker --change-interfacedocker0 systemctl restart firewalld 问题二、启动容器报 ptables failed/iptables: No chain/target/…...

ChemDraw 2023|Win英文|化学结构编辑器|安装教程

软件下载 【名称】&#xff1a;ChemDraw 2023 【大小】&#xff1a;1.34G 【语言】&#xff1a;英文界面 【安装环境】&#xff1a;Win10/Win11 【夸克网盘下载链接】&#xff08;务必手机注册&#xff09;&#xff1a; https://pan.quark.cn/s/320bcb67da80 【网站下载…...

Vue3实现提示文字组件

Vue3 实现一个文字提示组件&#xff08;Tooltip&#xff09; 文字提示&#xff08;Tooltip&#xff09;是前端开发中非常常见的组件&#xff0c;通常用于在用户悬停某个元素时显示额外的信息。 一、需求分析 我们要实现一个 Vue3 的文字提示组件&#xff0c;具备以下功能&…...

JAVA与C语言之间的差异(一)

一、代码习惯以及主函数 JAVA中{在使用的时候不要换行 public static void main(String[] args) {int[] array {1, 2, 3};for(int i 0; i < array.length; i){System.out.println(array[i] " ");}} 其次&#xff0c;以main函数为主函数&#xff1a; public …...

深入剖析 C 语言中的指针数组与数组指针

资料合集下载链接: ​​https://pan.quark.cn/s/472bbdfcd014​​ 在C语言中,指针是其强大和灵活性的核心。然而,围绕指针的概念有很多容易混淆的地方,其中“指针数组”和“数组指针”就是一对常见的“双胞胎”概念。它们名称相似,但含义和用法却大相径庭。 本文旨在清…...

4.1.1 Spark SQL概述

Spark SQL是Apache Spark的一个模块&#xff0c;专门用于处理结构化数据。它引入了DataFrame这一编程抽象&#xff0c;DataFrame是带有Schema信息的分布式数据集合&#xff0c;类似于关系型数据库中的表。用户可以通过SQL、DataFrames API和Datasets API三种方式操作结构化数据…...

【VSCode-Qt】Docker远程连接的项目UI文件在 VSCode 上无法预览

Docker远程连接的UI文件在 VSCode 上无法预览&#xff0c;通常是因为 VSCode 通过远程开发扩展&#xff08;Remote - SSH/Docker&#xff09;连接到 Docker 容器时&#xff0c;某些图形化功能未正确配置或支持。以下是可能原因和解决方案&#xff1a; 原因分析 X11 转发未配置…...

redis五种数据结构详解(java实现对应的案例)

一、简述 Redis是一款高性能的键值对存储数据库&#xff0c;它支持五种基本数据类型&#xff0c;分别是字符串(String)、列表(List)、哈希(Hash)、集合(Set)、有序集合(Sorted Set)。 二、五种基本数据类型 2.1 字符串(String) String是Redis最基本的类型&#xff0c;一个key对…...

Telnet 命令详解

Telnet 命令详解&#xff1a;从基础到实战应用 Telnet 是一种历史悠久的网络协议&#xff0c;广泛用于远程登录和管理设备。尽管如今更安全的 SSH 协议已逐渐取代其地位&#xff0c;但 Telnet 在特定场景下依然发挥着重要作用。本文将深入解析 Telnet 命令的参数、使用场景及注…...

深度解析新能源汽车结构与工作原理

一、核心系统架构 新能源汽车主要由三大核心系统构成&#xff1a; 电力驱动系统&#xff1a;包含永磁同步电机、电机控制器&#xff08;MCU&#xff09;及减速器&#xff0c;采用三合一集成设计实现轻量化。永磁同步电机通过电磁感应原理将电能转化为机械能&#xff0c;其效率可…...

React 生命周期与 Hook:从原理到实战全解析

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 持续学习&#xff0c;不断…...

OpenSSL 与 C++ 搭建一个支持 TLS 1.3 的服务器

好的&#xff0c;我们可以使用 OpenSSL 与 C 搭建一个支持 TLS 1.3 的服务器。下面是&#xff1a; ✅ 一、完整示例代码&#xff08;基于 OpenSSL&#xff09; 使用 C 和 OpenSSL 创建一个简单的 TCP TLS 服务器&#xff0c;支持 TLS 1.3。 ✅ 代码&#xff1a;tls_server.cp…...