依赖:
<docx4j.version>6.1.1</docx4j.version>
<export.fo.version>8.1.1</export.fo.version>
<!--word 转 pdf -->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j</artifactId>
<version>${docx4j.version}</version>
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-export-fo</artifactId>
<version>${export.fo.version}</version>
</dependency>
工具类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.docx4j.Docx4J;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.org.apache.poi.util.IOUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class WordUtils {
public static void main(String[] args) throws Exception {
WordUtils.convertDocxToPdf("D:/test.docx","D:/test.pdf");
}
/**
* docx文档转换为PDF
* @param body 文档
* @param response 响应给前端
* @return pdf 输出流
* @throws Exception 可能为Docx4JException, FileNotFoundException, IOException等
*/
public static void convertDocxToPdf(byte[] body , HttpServletResponse response) throws Exception {
response.setContentType("application/pdf");
File docxFile = FileUtil.byteToFile(body, UUID.randomUUID().toString() + ".docx");
try {
WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(docxFile);
setFontMapper(mlPackage);
Docx4J.toPDF(mlPackage, response.getOutputStream());
}catch (Exception e){
e.printStackTrace();
log.error("docx文档转换为PDF失败");
}
FileUtil.deleteTempFile(docxFile);
}
/**
* docx文档转换为PDF
*
* @param pdfPath PDF文档存储路径
* @throws Exception 可能为Docx4JException, FileNotFoundException, IOException等
*/
public static void convertDocxToPdf(String docxPath, String pdfPath) throws Exception {
FileOutputStream fileOutputStream = null;
try {
File file = new File(docxPath);
fileOutputStream = new FileOutputStream(new File(pdfPath));
WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(file);
setFontMapper(mlPackage);
Docx4J.toPDF(mlPackage, new FileOutputStream(new File(pdfPath)));
}catch (Exception e){
e.printStackTrace();
log.error("docx文档转换为PDF失败");
}finally {
IOUtils.closeQuietly(fileOutputStream);
}
}
private static void setFontMapper(WordprocessingMLPackage mlPackage) throws Exception {
Mapper fontMapper = new IdentityPlusMapper();
fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei"));
fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
mlPackage.setFontMapper(fontMapper);
}
}
太多的word转pdf搜索出来的资料,版本号不是太旧,就是太繁琐,或者仅支持window,折腾了两天,最后还好找对了资料:https://blog.csdn.net/Jason_996/article/details/81707485
感谢这位博主。虽然版本有点旧,但我整了一下,发现居然只用了两个依赖就能实现了。注:数学部分特殊字符无法正常转换
相关工具类:
import java.util.Arrays;
public class CalculateUtil {
public static Integer add(Integer... integers){
return Arrays.stream(integers).filter(integer -> integer!=null).reduce(0, (a, b) -> a + b);
}
public static void main(String[] args) {
Integer integer = new Integer(1);
Integer first = null;
Integer add = add(integer, first);
System.out.println(add);
}
}
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public final class FileUtil {
public static final String XLSX_SUFFIX = ".xlsx";
private FileUtil() {
}
/**
* 文件转比特流
*/
public static byte[] fileToByte(String filePath) {
File file = new File(filePath);
return FileUtil.fileToByte(file);
}
/**
* 文件转比特流
*/
public static byte[] fileToByte(File file) {
byte[] buffer = null;
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
/**
* 比特流转文件
*/
public static File byteToFile(byte[] buf, String fileName) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try {
file = new File(fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(buf);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file;
}
/**
* 删除临时文件
*/
public static void deleteTempFile(File file) {
if (file == null) {
return;
}
boolean delete = file.delete();
if (!delete) {
log.error("删除临时文件失败");
}
}
/**
* 返回带点的后缀
*
* @param ext
* @return
*/
public static String getExt(String ext) {
return ext.indexOf(".") == -1 ? "." + ext : ext;
}
/**
* 返回一个临时文件名不带后缀
*
* @return
*/
public static String createTempFileName() {
String folder = System.getProperty("java.io.tmpdir");
String filename = folder + UUID.randomUUID();
return filename;
}
/**
* 截取文件的后缀名 无后缀返回“”
*
* @param fileName
* @return
*/
public static String cutFileName(String fileName) {
String ext = StringUtil.cutName(fileName, ".");
return ext == null ? "" : ext;
}
/**
* 生成一个临时文件
*/
public static File tempFile(String suffix) {
String folder = System.getProperty("java.io.tmpdir");
String fileName = System.currentTimeMillis() + suffix;
String s = folder + fileName;
return new File(s);
}
/**
* 生成临时文件和file文件名字一样的
*/
public static File tempFile(File file) {
String folder = System.getProperty("java.io.tmpdir");
String s = folder + file.getName();
return new File(s);
}
/**
* 创建一个临时目录 + 文件名字符串
*/
public static String getTempFileName(String fileName) {
String folder = System.getProperty("java.io.tmpdir");
return folder + "/" + fileName;
}
/**
* 同名文件命名, 例如 1. a.pdf --> a(1).pdf 2. a --> a(1) 3. a(1).pdf --> a(2).pdf
* 4. a(1) --> a(2)
*
* @param fileName
* @return
*/
public static String renameSameFileName(String fileName) {
String newFileName = null;
int i = fileName.lastIndexOf(".");
if (i != -1) { // 有同名文件,有.作为后缀
String rule = "(.*)\\.(.*)";
Matcher matcher = Pattern.compile(rule).matcher(fileName);
if (matcher.find()) {
String fileNameNoSuffix = matcher.group(1); // 文件名
String suffix = matcher.group(2);
String rule2 = "(.*)\\((\\d)\\)";
Matcher matcher1 = Pattern.compile(rule2).matcher(fileNameNoSuffix);
if (matcher1.find()) {// 同名的文件名是 文件名(1).pdf 这种
String number = matcher1.group(2);
Integer newNumber = CalculateUtil.add(Integer.valueOf(number), 1);
newFileName = fileNameNoSuffix.replaceAll(rule2, "$1").concat("(" + newNumber + ").")
.concat(suffix);
} else { // 同名的文件名是 文件名.pdf这种 直接添加 (1).pdf
newFileName = fileName.replaceAll(rule, "$1(1).$2");
}
}
} else {// 有同名文件,没有以.作为后缀
String rule2 = "(.*)\\((\\d)\\)";
Matcher matcher1 = Pattern.compile(rule2).matcher(fileName);
if (matcher1.find()) {// 同名的文件名是 文件名(1) 这种
String number = matcher1.group(2);
Integer newNumber = CalculateUtil.add(Integer.valueOf(number), 1);
newFileName = fileName.replaceAll(rule2, "$1").concat("(" + newNumber + ")");
} else {
newFileName = fileName.concat("(1)");
}
}
return newFileName;
}
/**
* 截取 /sdfs/sdfsdf.pdf 中的sdfsdf.pdf
*
* @param filePath
* @return
*/
public static String getFileNameByPath(String filePath) {
String rule = "(.*/)(.*)";
String fileName = filePath.replaceAll(rule, "$2");
return fileName;
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringUtil extends StringUtils {
/**
* 转换为下划线
*
* @param camelCaseName
* @return
*/
public static String underscoreName(String camelCaseName) {
StringBuilder result = new StringBuilder();
if (camelCaseName != null && camelCaseName.length() > 0) {
result.append(camelCaseName.substring(0, 1).toLowerCase());
for (int i = 1; i < camelCaseName.length(); i++) {
char ch = camelCaseName.charAt(i);
if (Character.isUpperCase(ch)) {
result.append("_");
result.append(Character.toLowerCase(ch));
} else {
result.append(ch);
}
}
}
return result.toString();
}
/**
* 转换为驼峰
*
* @param underscoreName
* @return
*/
public static String camelCaseName(String underscoreName) {
StringBuilder result = new StringBuilder();
if (underscoreName != null && underscoreName.length() > 0) {
boolean flag = false;
for (int i = 0; i < underscoreName.length(); i++) {
char ch = underscoreName.charAt(i);
if ("_".charAt(0) == ch) {
flag = true;
} else {
if (flag) {
result.append(Character.toUpperCase(ch));
flag = false;
} else {
result.append(ch);
}
}
}
}
return result.toString();
}
/**
* 截取文件后缀
*/
public static String cutName(String fileName,String cutString){
int i = fileName.lastIndexOf(cutString);
if (i==-1) {
return null;
}else{
return fileName.substring(i + 1);
}
}
/**
* 劈开某个字符串得到list
*/
public static List<String> splitString(String source,String str){
List<String> list = new ArrayList<>();
String[] split = source.split(str);
Collections.addAll(list,split);
return list;
}
/**
* 去除正则的特殊符号 ( )
*/
public static String removeRegex(String source){
return source.replaceAll("\\(|\\)", "");
}
/**
* 去除空白符 再去除 正则特殊符号
*/
public static String removeBlankAndRegex(String source){
return removeRegex(removeBlank(source));
}
/**
* 去除空白符
*/
public static String removeBlank(String source){
return source.replaceAll("\\s", "");
}
/**
* 正则匹配
* @param source
* @param rule
* @return
*/
public static Matcher match(String source,String rule){
Pattern compile = Pattern.compile(rule);
Matcher matcher = compile.matcher(source);
if (matcher.find()) {
return matcher;
}
return null;
}
public static String mybitsIds(List<Integer> list, String splits){
String join = org.apache.commons.lang3.StringUtils.join(list, splits);
return addAfterAndBefore("(", join, ")");
}
/**
* 在string的前后添加字符
* @param after
* @param source
* @param before
* @return
*/
public static String addAfterAndBefore(String after,String source,String before){
StringBuilder stringBuilder = new StringBuilder(after);
return stringBuilder.append(source).append(before).toString();
}
/**
* 两个字符串中间添加字符串
* @param header
* @param tail
* @param middle
* @return
*/
public static String addMiddle(String header,String tail,String... middle){
StringBuilder stringBuilder = new StringBuilder(header);
for (String s : middle) {
stringBuilder.append(s);
}
return stringBuilder.append(tail).toString();
}
/**
* 拼接带有参数的url,url后面有?拼接成 &xxx=xxx,没有?拼接?
* @param url
* @param param
* @return
*/
public static String concatUrl(String url,String... param){
StringBuilder stringBuilder = new StringBuilder(url);
String join = String.join("&", param);
if (url.indexOf("?")!=-1) {
return stringBuilder.append("&").append(join).toString();
}else {
StringBuilder append = stringBuilder.append("?");
return append.append(join).toString();
}
}