1 2 3 4

OSS下载WORD文档转PDF实现

方案:LibreOffice 转换质量高,支持复杂格式 需要安装外部程序

无需额外依赖

代码部分

@SysLog("花名册-线上签订合同下载")
    @PostMapping("/downLoadContract")
    @ApiOperation(value = "花名册-线上签订合同下载", notes = "花名册-线上签订合同下载")
    public void downLoadContract(@RequestParam String contractUrl, HttpServletResponse response) {
        try {
            if (contractUrl.startsWith(ossConfig.getBucketOuterUrl())) {
                contractUrl = contractUrl.replaceAll(ossConfig.getBucketOuterUrl() + "/", "");
            } else if (contractUrl.startsWith("/")) {
                contractUrl = contractUrl.substring(1);
            }
            // 4. 根据文件类型进行转换
            if (contractUrl.toLowerCase().endsWith(".docx")) {
                // 设置输出文件名
                String outputFilename = contractUrl.substring(contractUrl.lastIndexOf('/') + 1).replace(".docx", ".pdf");
                // 执行转换
                libreOfficeConverter.convertOssWordToPdf(contractUrl, response, outputFilename);
            } else if (contractUrl.toLowerCase().endsWith(".doc")) {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().print("{\"code\":1,\"msg\":\"暂不支持doc文件\"}");
            } else {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().print("{\"code\":1,\"msg\":\"不支持的文件格式\"}");
            }
        } catch (Exception e) {
            log.error("花名册-线上签订合同下载失败:{}", e.getMessage());
        }
    }
package com.cloud.rapid.common.core.util;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Component
public class LibreOfficeConverter {

    @Resource
    private OssUtils ossUtils;
    // LibreOffice安装路径(根据系统配置)
    @Value("${libreoffice.path:C:\\Program Files\\LibreOffice\\program\\soffice.exe}")
    private String libreOfficePath;
    // 临时文件目录
    @Value("${libreoffice.temp.dir:D:\\cjq\\temp}")
    private String tempDir;

    /**
     * 将OSS上的Word文件转换为PDF并输出到HttpServletResponse
     *
     * @param objectKey      OSS文件路径
     * @param response       HttpServletResponse
     * @param outputFilename 输出文件名
     */
    public void convertOssWordToPdf(String objectKey, HttpServletResponse response, String outputFilename) throws Exception {
        // 创建唯一工作目录
        String workDir = createUniqueWorkDir();
        Path tempWorkDir = Paths.get(workDir);
        try {
            // 1. 下载OSS文件到临时目录
            Path inputFile = downloadOssFile(objectKey, workDir);
            // 2. 使用LibreOffice转换为PDF
            Path outputFile = convertToPdf(inputFile, workDir);
            // 3. 设置响应头
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + outputFilename + "\"");
            // 4. 将PDF文件写入响应流
            try (InputStream in = Files.newInputStream(outputFile); OutputStream out = response.getOutputStream()) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }
        } finally {
            // 5. 清理临时文件
            deleteDirectory(tempWorkDir.toFile());
        }
    }

    /**
     * 从OSS下载文件到临时目录
     */
    private Path downloadOssFile(String objectKey, String workDir) throws IOException {
        String fileName = objectKey.substring(objectKey.lastIndexOf('/') + 1);
        Path outputPath = Paths.get(workDir, fileName);
        try (InputStream inputStream = ossUtils.download(objectKey).getObjectContent(); FileOutputStream outputStream = new FileOutputStream(outputPath.toFile())) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
        return outputPath;
    }

    /**
     * 使用LibreOffice将文件转换为PDF
     */
    private Path convertToPdf(Path inputFile, String workDir) throws IOException, InterruptedException {
        // 准备输出文件路径
        String inputFileName = inputFile.getFileName().toString();
        String outputFileName = inputFileName.substring(0, inputFileName.lastIndexOf('.')) + ".pdf";
        Path outputPath = Paths.get(workDir, outputFileName);

        // 构建转换命令
        String command = String.format("%s --headless --convert-to pdf --outdir %s %s", libreOfficePath, workDir, inputFile.toAbsolutePath());

        // 执行转换命令
        Process process = Runtime.getRuntime().exec(command);

        // 等待转换完成
        int exitCode = process.waitFor();

        // 检查转换是否成功
        if (exitCode != 0 || !Files.exists(outputPath)) {
            // 读取错误信息
            StringBuilder error = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    error.append(line).append("\n");
                }
            }
            throw new IOException("PDF转换失败 (退出码: " + exitCode + ")\n" + error);
        }

        return outputPath;
    }

    /**
     * 创建唯一工作目录
     */
    private String createUniqueWorkDir() throws IOException {
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String randomId = UUID.randomUUID().toString().substring(0, 8);
        Path path = Paths.get(tempDir, "convert_" + timestamp + "_" + randomId);
        Files.createDirectories(path);
        return path.toString();
    }

    /**
     * 递归删除目录
     */
    private void deleteDirectory(File directory) {
        if (!directory.exists()) return;

        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    file.delete();
                }
            }
        }
        directory.delete();
    }
}
View Code
libreoffice:
  path: /usr/bin/libreoffice  #看服务器上的实际情况
#path: C:\Program Files\LibreOffice\program\soffice.exe   # win实际目录    
  temp:
    dir: /opt/tmp

本地安装部分

https://zh-cn.libreoffice.org/download/libreoffice/   下载windows版本  本地安装后即可使用

Linux服务器安装部分

华为云和阿里云  操作系统版本不同   略有差异

华为云

sudo yum install libreoffice
# 添加中文依赖 对于 CentOS/RHEL 7 及以下版本
sudo yum install -y google-noto-sans-simplified-chinese-fonts
# 添加中文依赖 对于 CentOS/RHEL 8 及以上版本
sudo dnf install -y google-noto-sans-sans-simplified-chinese-fonts

阿里云

官网下载RPM文件: LibreOffice_25.2.4_Linux_x86-64_rpm.tar.gz  放在opt目录下

进入服务器opt目录下

tar -zxvf LibreOffice_25.2.4_Linux_x86-64_rpm.tar.gz
cd LibreOffice_25.2.4.2_Linux_x86-64_rpm/RPMS/
sudo yum localinstall -y *.rpm
libreoffice25.2 --version

输出类似:
LibreOffice 25.2.4.2 (X86_64) / LibreOffice Community

如有问题:/opt/libreoffice25.2/program/soffice.bin: error while loading shared libraries: libX11-xcb.so.1: cannot open shared object file: No such file or directory

sudo yum install -y libX11-xcb
sudo yum groupinstall -y "X Window System"
sudo yum install -y libXinerama libXcursor libXrandr

验证: ldconfig -p | grep libX11-xcb

#安装中文字体
sudo yum install -y wqy-microhei-fonts

具体看下/usr/bin目录下的是libreoffice文件还是libreoffice25.2文件

可以酌情修改名称   libreoffice -version

LibreOffice 25.2.4.3

 

执行libreoffice25.2 --headless --invisible --convert-to pdf /opt/xxx.docx --outdir /opt 命令进行测试(先在/opt/下生成一个docx文件)

posted @ 2025-06-16 16:14  一缕清风丶  阅读(35)  评论(0)    收藏  举报