java word转pdf工具类,兼容linux和windows服务器

如果需要linux使用,可参考这篇文章https://blog.csdn.net/weixin_45559862/article/details/154842845?spm=1001.2014.3001.5501

依赖包

java 复制代码
   <!--word 2 pdf start-->
        <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>

代码,注意,方法的返回值可自定义,不需要删除即可。

java 复制代码
package org.springblade.modules.api.utils;

import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import lombok.extern.slf4j.Slf4j;
import org.springblade.modules.api.entity.NaReport;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ExportWordToPdfUtil {

    /**
     * Word转PDF(根据操作系统自动选择转换方式)
     *
     * @param filePath    源文件路径
     * @param outFilePath 输出文件路径
     * @return NaReport对象,包含文件信息
     */
    public static NaReport wordToPdf(String filePath, String outFilePath) {
        NaReport naReport = new NaReport();
        File wordFile = new File(filePath);
        File pdfFile = new File(outFilePath);

        // 确保输出目录存在
        File parentDir = pdfFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        // 如果输出文件已存在则删除
        if (pdfFile.exists()) {
            if (!pdfFile.delete()) {
                log.warn("无法删除已存在的文件: {}", outFilePath);
            }
        }

        // 获取当前系统名称
        String osName = System.getProperty("os.name").toLowerCase();
        boolean success = false;

        // 根据系统选择执行方法
        if (osName.contains("win")) {
            success = winWordToPdf(pdfFile, wordFile);
        } else if (osName.contains("nux") || osName.contains("nix")) {
            success = linuxWordToPdf(pdfFile, wordFile);
        } else {
            log.error("不支持的操作系统: {}", osName);
            return null;
        }

        if (success && pdfFile.exists()) {
            // 设置NaReport对象属性
            naReport.setSize(smartConvert(pdfFile.length()));
            naReport.setUrl(pdfFile.getAbsolutePath());
            naReport.setFileType(getFileExtension(pdfFile));
            log.info("文件转换成功: {}", outFilePath);
            return naReport;
        } else {
            // 转换失败时删除可能生成的不完整文件
            if (pdfFile.exists()) {
                pdfFile.delete();
            }
            log.error("文件转换失败: {}", filePath);
            return null;
        }
    }

    /**
     * windows系统word转pdf
     * @param pdfFile 转换后的pdf文件
     * @param wordFile word源文件
     * @return 是否转换成功
     */
    private static boolean winWordToPdf(File pdfFile, File wordFile) {
        IConverter converter = null;
        try {
            converter = LocalConverter.builder()
                    .baseFolder(new File(pdfFile.getParent()))
                    .build();

            Future<Boolean> conversion = converter.convert(new FileInputStream(wordFile))
                    .as(DocumentType.DOCX)
                    .to(new FileOutputStream(pdfFile))
                    .as(DocumentType.PDF)
                    .schedule();

            return conversion.get(2, TimeUnit.MINUTES);
        } catch (Exception e) {
            log.error("Windows环境Word转PDF失败", e);
            return false;
        } finally {
            if (converter != null) {
                converter.shutDown();
            }
        }
    }

    /**
     * linux系统word转pdf
     * 使用LibreOffice转换。系统需安装LibreOffice
     * @param pdfFile 转换后的pdf文件
     * @param wordFile word源文件
     * @return 是否转换成功
     */
    private static boolean linuxWordToPdf(File pdfFile, File wordFile) {
        // 获取word文件的绝对路径
        String sourcePath = wordFile.getAbsolutePath();
        // 获取pdf文件存放文件夹的绝对路径
        String outDir = pdfFile.getParent();

        // 构建LibreOffice的命令行工具命令
        String command = String.format("libreoffice --invisible --convert-to pdf --outdir %s %s", 
                outDir, sourcePath);
        log.info("执行转换命令: {}", command);

        // 执行转换命令
        boolean cmdSuccess = executeLinuxCmd(command);
        
        if (cmdSuccess) {
            // 检查是否生成对应的PDF文件(LibreOffice生成的文件名基于源文件名)
            String generatedPdfName = wordFile.getName().replaceAll("\\.(doc|docx)$", ".pdf");
            File generatedPdf = new File(outDir, generatedPdfName);
            
            if (generatedPdf.exists()) {
                // 如果生成的文件名与目标文件名不同,需要重命名
                if (!generatedPdf.getName().equals(pdfFile.getName())) {
                    return generatedPdf.renameTo(pdfFile);
                }
                return true;
            }
        }
        return false;
    }

    /**
     * 执行命令行
     * @param cmd 命令行
     * @return 是否执行成功
     */
    private static boolean executeLinuxCmd(String cmd) {
        try {
            Process process = Runtime.getRuntime().exec(new String[]{"sh", "-c", cmd});
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (InterruptedException e) {
            log.error("执行Linux命令被中断: ", e);
            Thread.currentThread().interrupt();
            return false;
        } catch (IOException e) {
            log.error("执行Linux命令IO异常: ", e);
            return false;
        }
    }

    /**
     * 智能转换文件大小(自动选择KB或MB)
     * @param bytes 文件大小(字节)
     * @return 格式化后的文件大小字符串
     */
    private static String smartConvert(long bytes) {
        if (bytes < 1024 * 1024) { // 小于1MB
            return toKB(bytes);
        } else {
            return toMB(bytes);
        }
    }

    /**
     * 转换为KB(保留两位小数)
     * @param bytes 文件大小(字节)
     * @return KB大小的字符串表示
     */
    private static String toKB(long bytes) {
        double kb = bytes / 1024.0;
        return String.format("%.2f KB", kb);
    }

    /**
     * 转换为MB(保留两位小数)
     * @param bytes 文件大小(字节)
     * @return MB大小的字符串表示
     */
    private static String toMB(long bytes) {
        double mb = bytes / (1024.0 * 1024.0);
        return String.format("%.2f MB", mb);
    }

    /**
     * 获取文件后缀
     * @param file 文件对象
     * @return 文件扩展名(小写)
     */
    private static String getFileExtension(File file) {
        String fileName = file.getName();
        int dotIndex = fileName.lastIndexOf('.');
        if (dotIndex == -1 || dotIndex == 0 || dotIndex == fileName.length() - 1) {
            return "";
        }
        return fileName.substring(dotIndex + 1).toLowerCase();
    }

    public static void main(String[] args) {
        // 测试代码
        String filePath = "F:\\machine\\naReport\\20251022\\1761124217178naReport.docx";
        String outFilePath = "F:/machine/naReport/20251022/1761124217178naReport-转换.pdf";

        NaReport result = wordToPdf(filePath, outFilePath);
        if (result != null) {
            System.out.println("转换成功:");
            System.out.println("文件大小: " + result.getSize());
            System.out.println("文件路径: " + result.getUrl());
            System.out.println("文件类型: " + result.getFileType());
        } else {
            System.out.println("转换失败");
        }
    }
}
相关推荐
任子菲阳1 小时前
学Java第四十五天——不可变集合、Stream流
java·开发语言·windows
CodeCraft Studio2 小时前
Excel处理控件Aspose.Cells教程:使用Python从Excel工作表中删除数据透视表
开发语言·python·excel·aspose·aspose.cells·数据透视表
开开心心_Every2 小时前
Excel图片提取工具,批量导出无限制
学习·pdf·华为云·.net·excel·harmonyos·1024程序员节
学IT的周星星2 小时前
SpringMVC请求参数的绑定
java·开发语言
yangshuquan2 小时前
C# 委托和事件的3点区别,你知道几个?
c#·委托·事件·编程技巧
普通网友2 小时前
高性能TCP服务器设计
开发语言·c++·算法
普通网友2 小时前
C++与硬件交互编程
开发语言·c++·算法
Elias不吃糖3 小时前
整合了c++里面常用的STL及其常用API
开发语言·c++·学习·stl
E***q5393 小时前
后端服务限流实现,Spring Cloud Alibaba Sentinel
java·开发语言·sentinel