实现将docx转成PDF

最近实现了一个将docx转成PDF的功能,这里来记录一下实现过程

我是参考这篇文章Java将Word转换成PDF的常用用法_java_脚本之家

实现步骤基本上是按照上面文档中描述的内容,把大象装冰箱一共就三步

1、导入依赖

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>wordToPDF</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.5</version>
            <scope>compile</scope>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
        </dependency>

        <!--word转换为PDF文档-->
        <dependency>
            <groupId>com.documents4j</groupId>
            <artifactId>documents4j-local</artifactId>
            <version>1.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.documents4j</groupId>
            <artifactId>documents4j-transformer-msoffice-word</artifactId>
            <version>1.0.3</version>
        </dependency>

    </dependencies>

</project>

2、增加日志的配置文件(这一步可以忽略)

application.yml

XML 复制代码
logging:
  config: classpath:log4j2.xml

log4j2.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="INFO" monitorInterval="30">
    <Properties>
        <property name="ALL_LOG_FILE_NAME">
            log/
        </property>
        <!-- 输出日志的格式 -->
        <property name="PATTERN">[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%M-%t] [%-5level] %logger{36}:%L - %msg%n</property>
    </Properties>
    <Appenders>
        <!--这个输出控制台的配置 -->
        <Console name="Console" target="SYSTEM_OUT">
            <!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>

            <PatternLayout pattern="${PATTERN}"/>
        </Console>
        <RollingFile name="RollingFileAll"
                     fileName="${ALL_LOG_FILE_NAME}/all.log"
                     filePattern="${ALL_LOG_FILE_NAME}/all-%d{yyyy-MM-dd}-%i.log">
            <Filters>
                <!--设置只输出级别为info的日志-->
                <ThresholdFilter level="all"/>
            </Filters>
            <!--文件输出格式-->
            <PatternLayout pattern="${PATTERN}"/>
            <Policies>
                <!--每天一个文件-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--单个文件的大小-->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!--设置保留的文件数据-->
            <DefaultRolloverStrategy max="12">
                <!--删除的规则-->
                <Delete basePath="${ALL_LOG_FILE_NAME}" maxDepth="2">
                    <!--保存文件名-->
                    <IfFileName glob="all-*.log"/>
                    <!--保留天数-->
                    <IfLastModified age="30d"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>

    </Appenders>

    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.springframework" level="warn"/>
        <logger name="org.mybatis" level="warn"/>
        <logger name="org.apache.kafka" level="warn"/>
        <root level="info">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileAll"/>
        </root>
    </loggers>
</configuration>

3、核心代码

java 复制代码
package com.youyou;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConversionJobWithPriorityUnspecified;
import com.documents4j.api.IConversionJobWithSourceSpecified;
import com.documents4j.api.IConversionJobWithSourceUnspecified;
import com.documents4j.api.IConversionJobWithTargetUnspecified;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@Slf4j
public class Documents4jUtil {

    public static void main(String[] args) throws FileNotFoundException {
        File file = FileUtil.touch("D:\\Desktop\\SIU测试工装使用方法2.pdf");
        try (InputStream inputStream = IoUtil.toStream(FileUtil.file("D:\\Desktop\\SIU测试工装使用方法.docx"));
             OutputStream outputStream = new FileOutputStream(file)) {

            convertWordToPdf(inputStream, outputStream);

            System.out.println("完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * word转pdf
     */
    public static void convertWordToPdf(InputStream stream, OutputStream sourceOutput) {
        String os = System.getProperty("os.name").toLowerCase();
        log.info("convertWordToPdf 当前操作系统:{}", os);
        if (os.contains("win")) {
            // Windows操作系统
            windowsWordToPdf(stream, sourceOutput);
        } else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {
            // Unix/Linux/Mac操作系统
            linuxWordToPdf(stream, sourceOutput);
        } else {
            // 未知操作系统
            throw new RuntimeException("不支持当前操作系统转换文档。");
        }
    }

    /**
     * 通过documents4j 实现word转pdf -- Windows 环境 需要有 Microsoft Office 服务
     */
    public static void windowsWordToPdf(InputStream stream, OutputStream sourceOutput) {
        try {
            IConverter converter = LocalConverter.builder().build();
            IConversionJobWithSourceUnspecified convert = converter.convert(stream);
            IConversionJobWithSourceSpecified sourceSpecified = convert.as(DocumentType.DOCX);
            IConversionJobWithTargetUnspecified to = sourceSpecified.to(sourceOutput);
            IConversionJobWithPriorityUnspecified priorityUnspecified = to.as(DocumentType.PDF);
            boolean execute = priorityUnspecified.execute();
            log.info("转换结果:{}", execute);
            converter.shutDown();
        } catch (Exception e) {
            log.error("winWordToPdf windows环境word转换为pdf时出现异常:", e);
        }
    }

    /**
     * 通过libreoffice 实现word转pdf -- linux 环境 需要有 libreoffice 服务
     */
    public static void linuxWordToPdf(InputStream stream, OutputStream sourceOutput) {
        // 创建临时文件
        File tempFile = createTempFileFromInputStream(stream);
        // 构建LibreOffice的命令行工具命令
        String command = "libreoffice6.4 --headless --invisible --convert-to pdf " + tempFile.getAbsolutePath() + " --outdir " + tempFile.getParent();
        // 执行转换命令
        try {
            if (!executeLinuxCmd(command)) {
                throw new IOException("转换失败");
            }
            readPdfFileToByteArrayOutputStream(tempFile, sourceOutput);
        } catch (Exception e) {
            log.error("ConvertWordToPdf: Linux环境word转换为pdf时出现异常:" + e + tempFile.getPath());
            // 清理临时文件
            tempFile.delete();
        } finally {
            File pdfFile = new File(tempFile.getParent(), tempFile.getName().replace(".docx", ".pdf"));
            //清理转换后的pdf文件
            pdfFile.delete();
            // 清理临时文件,无论是否成功转换
            tempFile.delete();
        }
    }

    /**
     * 执行命令行
     *
     * @param cmd 命令行
     * @return
     * @throws IOException
     */
    private static boolean executeLinuxCmd(String cmd) throws IOException {
        Process process = Runtime.getRuntime().exec(cmd);
        try {
            process.waitFor();
        } catch (InterruptedException e) {
            log.error("executeLinuxCmd 执行Linux命令异常:", e);
            Thread.currentThread().interrupt();
            return false;
        }
        return true;
    }

    /**
     * 创建临时文件
     */
    private static File createTempFileFromInputStream(InputStream inputStream) {
        try {
            File tempFile = File.createTempFile("temp_word", ".docx");
            Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            return tempFile;
        } catch (IOException e) {
            log.error("创建临时文件失败:", e);
            throw new RuntimeException("创建临时文件失败", e);
        }
    }

    /**
     * 读取pdf文件
     */
    private static void readPdfFileToByteArrayOutputStream(File tempFile, OutputStream sourceOutput) {
        try {
            Path outputFile = Paths.get(tempFile.getParent(), tempFile.getName().replace(".docx", ".pdf"));
            Files.copy(outputFile, sourceOutput);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

同时我也把相关代码上传到了gitee上地址如下:

word转PDF示例: documents4j组件将word文档转成pdf

相关推荐
南风微微吹11 小时前
最新国考《行测+申论》历年真题及答案解析电子版pdf(2000-2026年)
pdf
wujian831112 小时前
豆包导出pdf方法
人工智能·ai·pdf·豆包·deepseek·ai导出鸭
俊哥工具15 小时前
鼠标自动连点怎么设置?详细教学,简单易懂!
python·django·pdf·计算机外设·virtualenv·pygame
2601_9503160617 小时前
塞尔达攻略+塞尔达设定集+塞尔达传说攻略
游戏·pdf·电视盒子
SunnyDays101118 小时前
Java 实现 PDF 附件的添加与删除:四种实用方法
java·pdf·附件
小小尚@18 小时前
AI 加持!Adobe Acrobat DC 2026 解锁 PDF 高效办公新体验
人工智能·pdf
竹之月18 小时前
【Auto CAD 2020】单张打印输出PDF图纸A0、A1尺寸,黑白颜色
经验分享·pdf·auto cad2020
SunnyDays101118 小时前
Java 实现 PDF 中文文本查找与高亮的四种方法
java·pdf·查找文字
wujian831119 小时前
千问 文心 元宝 Kimi导出pdf方法
人工智能·ai·pdf·豆包·deepseek
凌云若寒2 天前
BarTender许可 | 关于PDF打印数量说明
学习·pdf·产品经理·制造·软件需求