Java 实现 Word 转PDF方案

生成 Word 转 PDF

1. 转换方案选择

项目开发我主要使用过 AsposeLibreOffice,两者代码实现都很简单,转换效果也不错。其他生成 pdf 的方案,比如使用 html 转换、xml、或者直接操作 pdf 模板,实际使用代码逻辑繁琐不易理解,且转换生成效果一般。LibreOffice主要是后期做复杂的 pdf 模板导出,使用 word 难以动态填充内容,后来使用 excel,在 java中计算后填充 excel,设置好格式在转换拼接 pdf 最后输出。

  • Aspose:商业收费软件,免费版有水印。
  • LibreOffice:开源免费, 需要部署环境安装LibreOffice,实际使用需要控制并发与文件大小,避免对服务器整体造成影响。

2. Aspose 实现方案

a. 依赖注入

可以直接下载 jar 包,注入 maven 依赖后直接使用:

<dependency>
  <groupId>com.aspose</groupId>
  <artifactId>aspose-words</artifactId>
  <version>15.8.0</version>
  <scope>system</scope>
  <systemPath>${project.basedir}/src/main/resources/lib/aspose-words-15.8.0-jdk16.jar</systemPath>
</dependency>
b. 实际使用

基本用法:

// 先创建一个临时文件用来存储 PDF
String pdfPath = FileUtils.getTempDirectoryPath() + System.currentTimeMillis() + ".pdf";

/**  
 * 加载license 用于破解 不生成水印  
 */  
@SneakyThrows  
private static void getLicense() {  
    try (InputStream is = AsposeUtil.class.getClassLoader().getResourceAsStream("lib/License.xml")) {  
        License license = new License();  
        license.setLicense(is);  
    }  
}

/**
 * word转pdf
 *
 * @param wordPath word文件保存的路径
 * @param pdfPath  转换后pdf文件保存的路径
 */
public static void wordToPdf(String wordPath, String pdfPath) throws Exception {
    // 获取许可证
    getLicense();
    // 加载 Word 文档
    Document doc = new Document(wordPath);
    // 设置 PdfSaveOptions
    PdfSaveOptions options = new PdfSaveOptions();
    options.setSaveFormat(SaveFormat.PDF);
    // 保存为 PDF
    try (FileOutputStream os = new FileOutputStream(pdfPath)) {
        doc.save(os, options);
    }
}
<License>  
    <Data>  
        <Products>  
            <Product>Aspose.Total for Java</Product>  
            <Product>Aspose.Words for Java</Product>  
        </Products>  
        <EditionType>Enterprise</EditionType>  
        <SubscriptionExpiry>20991231</SubscriptionExpiry>  
        <LicenseExpiry>20991231</LicenseExpiry>  
        <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>  
    </Data>  
    <Signature>        sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=  
    </Signature>  
</License>

c. 常见问题与解决思路
1. 字体文件缺失导致转换乱码
  • 场景:在服务器或 Docker 环境下运行,可能会因缺少字体导致 PDF 乱码。

  • 解决方案一:将字体文件放在服务器的字体目录,Docker 可在启动时拷贝字体。

    # 使用带完整字体库的基础镜像
    FROM openjdk:17-jdk-slim
    # 拷贝字体
    COPY fonts/ /usr/share/fonts/truetype/custom/
    # 刷新字体缓存
    RUN fc-cache -fv
    
  • 解决方案二:将字体文件放在项目的 resources/fonts 目录下,导出时拷贝到临时目录后再进行转换(只需转换一次)。

    private final static String[] FONT_PATHS = {"fonts/Songti.ttc"};
    fontPath = copyTempFileFont(FONT_PATHS);
    
    /**
     * 将项目中的字体文件拷贝到临时目录
     * @return 字体目录路径
     */
    private static String copyTempFileFont(String... fontPath) {
        String tempDir = System.getProperty("java.io.tmpdir");
        File fontDir = new File(tempDir, "fonts");
        if (!fontDir.exists()) {
            fontDir.mkdirs(); // 创建目录
        }
        for (String path : fontPath) {
            File tempFile = new File(fontDir, new File(path).getName());
            if (!tempFile.exists()) {
                try (InputStream inputStream = Object.class.getClassLoader().getResourceAsStream(path)) {
                    FileUtils.copyInputStreamToFile(inputStream, tempFile);
                } catch (IOException e) {
                    throw new RuntimeException("字体文件转换失败,请稍候重试");
                }
            }
        }
        return fontDir.getPath() + "/";
    }
    

    带字体目录的转换方法:

    /**
     * word转pdf(指定字体目录)
     *
     * @param wordPath word文件保存的路径
     * @param pdfPath  转换后pdf文件保存的路径
     * @param fontPath 字体目录
     */
    public static void wordToPdf(String wordPath, String pdfPath, String fontPath) throws Exception {
        // 获取许可证
        getLicense();
        // 设置字体文件夹
        FontSettings.setFontsFolder(fontPath, false);
        // 加载 Word 文档
        Document doc = new Document(wordPath);
        // 设置 PdfSaveOptions
        PdfSaveOptions options = new PdfSaveOptions();
        options.setSaveFormat(SaveFormat.PDF);
        // 保存为 PDF
        try (FileOutputStream os = new FileOutputStream(new File(pdfPath))) {
            doc.save(os, options);
        }
    }
    

3. LibreOffice 实现方案(对应 excel 也可以直接使用)

  1. 官网下载安装: https://zh-cn.libreoffice.org/
a. JODConverter(调用 LibreOffice 转换)
  1. 引入依赖
<dependency>
    <groupId>org.jodconverter</groupId>
    <artifactId>jodconverter-local</artifactId>
    <version>4.4.4</version>
</dependency>
  1. 代码实现
/**
 * 转换为PDF(同时适用于 word excel)
 * @param file
 * @return
 * @throws OfficeException
 * @throws IOException
 */
public File convertToPdf(File file) throws OfficeException, IOException {
    File tempPdfFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), ".pdf");
    LocalOfficeManager officeManager = null;
    try {
        officeManager = (LocalOfficeManager.builder().install()).build();
        officeManager.start();
        (LocalConverter.builder().officeManager(officeManager)).build().convert(file).to(tempPdfFile).execute();
    } finally {
        if (officeManager != null) {
            officeManager.stop();
        }
    }
    return tempPdfFile;
}
  1. 拼接pdf
    a. 依赖
<dependency>  
    <groupId>com.itextpdf</groupId>  
    <artifactId>itext7-core</artifactId>  
    <version>7.1.15</version>  
</dependency>

b. 实现
/**  
 * 合并PDF文件  
 */  
private void mergePdfFiles(List<File> pdfFiles, String outputPath) throws IOException {  
    try (PdfWriter writer = new PdfWriter(outputPath);  
         PdfDocument mergedDoc = new PdfDocument(writer)) {  
        PdfMerger merger = new PdfMerger(mergedDoc);  
        for (File pdfFile : pdfFiles) {  
            try (PdfReader reader = new PdfReader(pdfFile);  
                 PdfDocument sourceDoc = new PdfDocument(reader)) {  
                merger.merge(sourceDoc, 1, sourceDoc.getNumberOfPages());  
            }  
        }  
    }  
}

4. 部署服务器、docker需要安装LibreOffice, 需要安装字体文件

DockerFile 参考示例:

# 使用带完整字体库的基础镜像
FROM openjdk:17-jdk-slim

# 1. 设置阿里云源并安装依赖(含中文字体支持)
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/debian bookworm main contrib non-free" > /etc/apt/sources.list && \
    apt-get update && \
    apt-get install -y --no-install-recommends \
        dpkg \
        libssl3 \
        libnss3 \
        libxslt1.1 \
        libdbus-1-3 \
        libnspr4 \
        libcurl4 \
        libgtk-3-0 \
        libglib2.0-0 \
        libxinerama1 \
        libcairo2 \
        libfreetype6 \
        libxcb-shm0 \
        libx11-xcb1 \
        libxrender1 \
        libxtst6 \
        libxml2 \
        openssl \
        fontconfig \
        fonts-dejavu \
        fonts-wqy-microhei && \
    ln -sf /usr/lib/x86_64-linux-gnu/libssl.so.3 /usr/lib/x86_64-linux-gnu/libssl3.so && \
    ldconfig && \
    rm -rf /var/lib/apt/lists/*

# 2. 拷贝中文字体(如 SimSun.ttc)并注册
COPY fonts/ /usr/share/fonts/truetype/custom/
RUN fc-cache -fv

# 3. 安装 LibreOffice
WORKDIR /tmp
COPY LibreOffice_25.2.3_Linux_x86-64_deb.tar.gz .
RUN tar -xzf LibreOffice_25.2.3_Linux_x86-64_deb.tar.gz && \
    DEB_DIR=$(find . -type d -name "LibreOffice*") && \
    dpkg -i $DEB_DIR/DEBS/*.deb && \
    rm -rf /tmp/LibreOffice*

# 4. 验证 LibreOffice 所有依赖
RUN ldd /opt/libreoffice25.2/program/soffice.bin | grep -v "not found"

# 5. 设置环境变量
ENV LIBREOFFICE_HOME=/opt/libreoffice25.2/program \
    PATH="${PATH}:/opt/libreoffice25.2/program" \
    LANG=C.UTF-8 \
    TZ=Asia/Shanghai
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孔.Chandler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值