依赖:
<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).pdfnewFileName = 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();}}