1、使用技术
linux:libreoffice
windows:dom4j
2、java代码
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安装
java
#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示例
java
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/localtime
RUN 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"; \
fi
COPY ../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);
//转为pdf
File file = WordToPdfUtils.wordToPdf(outputStream);