利用docx4j word转pdf

2023-11-09

依赖:

<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();
        }
    }

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

利用docx4j word转pdf 的相关文章

随机推荐

  • CVE-2021-3493漏洞复现案例(提权)

    下面复现需要在虚拟机中完成 CVE 2021 3493漏洞案例 可以在下面链接下载关于该漏洞的代码脚本 https github com inspiringz CVE 2021 3493 1 攻击工具及环境说明 在虚拟机上完成 Ubuntu
  • 【已更新】2023mothercup妈妈杯D题数学建模挑战赛思路代码-航空安全风险分析和飞行技术评估问题

    我们来看下D题 这道题是一道数据分析类题目 总共有五个小问 第一题是要求我们针对附件1的数据质量开展可靠性研究 提取与飞行安全相关的部分关键数据项 并对数据项的重要程度进行分析 第一步是对数据的可靠性分析 数据质量的可靠性研究主要包括数据完
  • win32 socket编程 示例(功能简单,完善)

    最近在做的一个项目要用到网络通信方面的内容 于是自学了下win32socket 原来自己学过计算机网络 只了解网络各层的原理 但没有真正的编程来实现这些原理 哎 不过现在还来得及 下面是自己的一个示例 虽然简单 但了解了它 就知道了最基本的
  • Idea 学生认证

    Idea 学生认证 具体步骤 认证地址 操作如图 具体步骤 认证地址 https www jetbrains com community education students 操作如图 学生邮箱会收到来信 认证完成
  • linux常用命令笔记(二)

    2020 03 18 一 echo 1 原文输出 双引号可加可不加 echo hello world echo hello world 2 输出变量的值 echo 变量名 echo PATH 输出环境变量PATH的值 注意 linux环境变
  • 每一代内存的读写速度大概是多少?

    每一代内存的读写速度大概是多少 原文 https zhidao baidu com question 1797460631148535467 html 内存 有核心频率 I O频率 等效频率 最后由等效频率而算出带宽 带宽就等于内存的速度
  • vite+react+ts+eslint+prettier构建react开发项目

    目录 一 构建项目 二 安装eslint和prettier的依赖 三 修改 eslintrc cjs 创建 prettierrc cjs 1 eslintrc cjs文件配置 2 prettierrc cjs文件配置 三 将错误显示在页面上
  • 蓝桥杯嵌入式CT117E-M4学习笔记08-串口通信实验

    文章目录 前言 一 实验原理 二 配置步骤 三 串口发送 1 直接使用HAL USART Transmit发送 2 使用重定向prtinf函数发送 四 串口接收 总结 前言 本节我们学习开发板的串口通信 一 实验原理 1 串口通信原理 详见
  • 浏览器的渲染机制、提升页面性能、错误监控上报

    js运行机制 微任务队列 事件循环 单线程 错误监控 CSRF防范 css盒模型 Dom事件 原型链
  • 接口测试工具-apipost

    apiost Postman Swagger Mock 功能特色 实现多人实时协作 接口自动化测试 选择接口 组成流程 执行流程 基于接口创建在线文档可分享 官网 Apipost API 文档 调试 Mock 测试一体化协作平台 API列表
  • 02.07_两个链表相交

    给你两个单链表的头节点 headA 和 headB 请你找出并返回两个单链表相交的起始节点 如果两个链表没有交点 返回 null 解法一 如果两个链表有相交 那么从后面看一定是相同的 所以只需要把长的移动到和短的链表一样的长度开始遍历即可
  • 低成本副业:开发小程序商城攻略

    随着互联网的普及和电子商务的兴起 越来越多的人选择做点副业 其中开发小程序商城是一个不错的选择 相比传统的实体店 小程序商城的成本更低 而且门槛更低 可以让更多的人参与到副业中来 那么 如何开发自己的小程序商城呢 下面为大家介绍步骤和技巧
  • STM32中遇到的问题--关于串口的一些常见问题

    在单片机的开发过程中 最常用的外设就是串口了 是用来进行bug纠错 log输出的常用工具 也是用来与外部通讯的常见协议之一 但是在使用串口的过程中难免会遇到一些问题 下面就我在工作遇到的一些问题做了一些记录 与大家分享 其实也是为了自己在以
  • [云原生专题-39]:K8S - 核心概念 - 存储抽象- pod配置文件的挂载ConfigMap

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 122856681 目录 前言 第1章
  • 安卓逆向入门指南:应用分析与反编译

    安卓逆向入门指南 应用分析与反编译 概述 简要介绍安卓逆向工程的基本概念和背景 解释逆向工程的目的和重要性 以及在安全审计和应用研究中的应用 应用分析 安卓应用文件结构的解析 介绍APK文件的结构 包括AndroidManifest xml
  • c#中new 后面大括号

    C new一个对象的时候 后面的参数不是用小括号吗 下面的大括号是怎么回事 不是数据为什么会用大括号 BarcodeWriter barcodeWriter new BarcodeWriter Format ZXing BarcodeFor
  • jmap、jstat、jinfo、jstack命令详解

    jmap jmap histo pid gt log txt 此命令可以用来查看内存信息 实例个数以及占用内存大小 num 序号 instances 实例数量 bytes 占用空间大小 class name 类名称 C is a char
  • Windows中.exe程序的启动过程和C/C++运行时库<转载>

    很是受益 Windows中 exe程序的启动过程和C C 运行时库 lt 转载 gt Windows系统中 exe后缀的文件一般可以双击运行 编程时 编译出来的最终结果一般也表现为一个exe程序和其他的为程序执行提供支持的dll 我们双击一
  • Unity3d-简单AR游戏

    Unity3d 简单AR游戏 一 图片识别与建模 Vufria模块的导入 首先是安装Vuforia 模块 2017版本后的可以直接使用Unity Hub安装 安装完成后可以直接在软件中使用 然后在菜单目录的GameObject gt Vuf
  • 利用docx4j word转pdf

    依赖