1、使用技术
linux:libreoffice windows:dom4j
2、java代码
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.UUID;@Slf4j
public class WordToPdfUtils {private static String OS_NAME = "os.name";private static String WINDOWS = "windows";private static String DOCX = ".docx";private static String PDF = ".pdf";private static String TEMP_PATH = "/tmp";public static File wordToPdf(MultipartFile inputWord) {boolean IS_WINDOWS = System.getProperty(OS_NAME).toLowerCase().contains(WINDOWS);File tempWordFile = transferToFile(inputWord);File pdfFile;try {if (IS_WINDOWS) {pdfFile = new File(UUID.randomUUID() + PDF);winWordToPdf(pdfFile, tempWordFile);} else {pdfFile = linuxWordToPdf(TEMP_PATH, tempWordFile);}return pdfFile;} finally {if (tempWordFile.exists()) {tempWordFile.delete();}}}public static File wordToPdf(ByteArrayOutputStream outputStream) {boolean IS_WINDOWS = System.getProperty(OS_NAME).toLowerCase().contains(WINDOWS);File tempWordFile = outputStreamToFile(outputStream, UUID.randomUUID() + PDF);File pdfFile;try {if (IS_WINDOWS) {pdfFile = new File(UUID.randomUUID() + PDF);winWordToPdf(pdfFile, tempWordFile);} else {pdfFile = linuxWordToPdf(TEMP_PATH, tempWordFile);}return pdfFile;} finally {if (tempWordFile.exists()) {tempWordFile.delete();}}}public static File outputStreamToFile(OutputStream outputStream, String fileName) {File file = new File(fileName);try (OutputStream fileOutput = new FileOutputStream(file)) {// 将数据从ByteArrayOutputStream转移到文件输出流((ByteArrayOutputStream) outputStream).writeTo(fileOutput);return file;} catch (IOException e) {log.error("outputStreamToFile error", e);return null;}}public static MultipartFile convert(File file) throws IOException {FileInputStream fi = new FileInputStream(file);return new MockMultipartFile("file",file.getName(), null, fi);}/*** windows系统word转pdf** @param pdfFile 转换后的pdf文件* @param wordFile word源文件*/public static void winWordToPdf(File pdfFile, File wordFile) {IConverter converter = LocalConverter.builder().build();FileInputStream fileInputStream = null;FileOutputStream fileOutputStream = null;try {fileInputStream = new FileInputStream(wordFile);fileOutputStream = new FileOutputStream(pdfFile);converter.convert(fileInputStream).as(DocumentType.DOCX).to(fileOutputStream).as(DocumentType.PDF).execute();} catch (FileNotFoundException fileNotFoundException) {throw new ResultException(GlobalCodeEnum.WORD2PDF_ERROR, "文件不存在");} finally {if (fileInputStream != null) {try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}if (fileOutputStream != null) {try {fileOutputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 创建具有唯一性的临时文件** @param originalFilename 原始文件名* @return 创建好的临时文件对象* @throws IOException 如果创建临时文件过程中出现IO异常*/private static File createUniqueTempFile(String originalFilename) throws IOException {String uniqueIdentifier = UUID.randomUUID().toString() + System.nanoTime();return File.createTempFile("temp-" + uniqueIdentifier + "-", "-" + originalFilename);}/*** 根据原始Word文件名生成对应的PDF文件名** @param wordFileName Word文件名* @return PDF文件名*/private static String getPdfFileName(String wordFileName) {return wordFileName.replaceFirst("[.][^.]+$", ".pdf");}/*** 设置PDF文件的HTTP响应头信息** @param response HTTP响应对象* @param originalFilename 原始文件名*/private static void setPdfResponseHeaders(HttpServletResponse response, String originalFilename) {response.setContentType("application/pdf");response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(getPdfFileName(originalFilename)) + "\"");}/*** linux系统word转pdf* 使用LibreOffice转换。系统需安装LibreOffice* 转换命令 libreoffice --invisible --convert-to pdf --outdir output_dir source_path* 转换后的pdf文件名使用的是源文件的名称,所以如果要指定输出文件名称,就需把源文件名称改成想要输出的名称** @param wordFile word源文件*/public static File linuxWordToPdf(String outPutPath, File wordFile) {try {// 构建LibreOffice的下一行工具命令String command = "libreoffice --headless --invisible --convert-to pdf:writer_pdf_Export " + wordFile.getAbsolutePath() + " --outdir " + outPutPath;log.info(command);// 执行转换命令if (executeLinuxCmd(command)) {return new File(outPutPath + File.separator + wordFile.getName().split("\\.")[0] + "." + wordFile.getName().split("\\.")[1]);}return null;} catch (Exception e) {log.error("linuxWordToPdf linux环境word转换为pdf时出现异常!", e);return null;}}/*** 执行命令行** @param command 命令行* @return*/private static boolean executeLinuxCmd(String command) throws IOException, InterruptedException {// 使用Java的ProcessBuilder来执行Linux命令ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", command);Process process = processBuilder.start();// 等待命令执行完成,并获取输出和错误流信息int exitCode = process.waitFor();if (exitCode != 0) {log.error("执行命令 {} 失败,退出码:{}", command, exitCode);return false;}return true;}private static File transferToFile(MultipartFile multipartFile) {String path = UUID.randomUUID() + DOCX;File file = new File(path);try {if (!file.exists()) {file.createNewFile();}FileCopyUtils.copy(multipartFile.getBytes(), file);} catch (Exception e) {throw new RuntimeException(e);}return file;}}
3、libreoffice
下载 LibreOffice | LibreOffice 简体中文官方网站 - 自由免费的办公套件
linux安装
#libreoffice的安装步骤#1.先将libreoffice的rpm文件上传至服务器
#2.将rpm压缩包解压到/opt目录下
tar -zxvf /tmp/LibreOffice_24.8.1_Linux_x86-64_rpm.tar.gz -C /opt/libreoffice
#3.进入解压目录
cd /opt/libreoffice/LibreOffice_24.8.1.2_Linux_x86-64_rpm/RPMS
#4.安装rpm包
yum localinstall *.rpm
#5.检查是否安装完成
libreoffice24.8 --version
dockerfile示例
FROM xxx/library/xxx-jdk17:1.0
USER 0
RUN mkdir -p /testdata/logs \
&& mkdir /usr/finance-lease \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtimeRUN cd /testdata && curl -O https://arthas.aliyun.com/arthas-boot.jar# 切换 Rocky Linux 的 dnf 源为阿里云镜像源
RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/rocky.repo && \sed -i 's|^#baseurl=http://dl.rockylinux.org|baseurl=http://mirrors.cloud.aliyuncs.com|g' /etc/yum.repos.d/rocky.repo && \dnf clean all && dnf makecache# 判断是否为 Linux 系统,如果是则安装 LibreOffice
RUN if [ -f /etc/os-release ]; then \if [ -x /usr/bin/apt-get ]; then \apt-get update && apt-get install -y libreoffice; \elif [ -x /usr/bin/yum ]; then \yum update -y && yum install -y libreoffice; \elif [ -x /usr/bin/dnf ]; then \dnf update -y && dnf install -y libreoffice; \elif [ -x /usr/bin/zypper ]; then \zypper refresh && zypper install -y libreoffice; \elif [ -x /usr/bin/pacman ]; then \pacman -Syu --noconfirm libreoffice; \elif [ -x /usr/bin/apk ]; then \apk add --no-cache libreoffice; \else \echo "Unrecognized package manager, skipping LibreOffice installation"; \fi; \else \echo "Not a Linux-based system, skipping LibreOffice installation"; \fiCOPY ../entrypoint.sh /usr/finance-lease/entrypoint.sh
COPY ./finance-lease-business/target/financelease.jar /usr/finance-lease/financelease.jar
EXPOSE 8097
EXPOSE 10091
ENTRYPOINT ["/bin/bash", "/usr/finance-lease/entrypoint.sh"]
4、使用示例
//获取文件输入流信息URL url = new URL(fileInfo.getOssFullPath());inputStream = url.openConnection().getInputStream();//注意不能直接使用XWPFDocument,会出现类型转换异常,直接使用子类MyXWPFDocument xwpfDocument = new MyXWPFDocument(inputStream);//填充合同模板变量值,生成合同文件WordExportUtil.exportWord07(xwpfDocument, templateParams);xwpfDocument.write(outputStream);//转为pdfFile file = WordToPdfUtils.wordToPdf(outputStream);