docx4j优势:
免费开源可商用,服务器无需安装office软件等
docx4j劣势:
性能效率相对于其他框架而言较差
复杂的word排版内容可能无法转换,对格式要求较高
适用场景:
对性能效率要求不高,word内容排版简单,后续无很强的应用需求

编码实现

项目框架环境:JDK1.8、SpringBoot2.3.1.RELEASE

maven

<docx4j.version>8.2.9</docx4j.version>
<dependency><groupId>org.docx4j</groupId><artifactId>docx4j-JAXB-Internal</artifactId><version>${docx4j.version}</version>
</dependency>
<dependency><groupId>org.docx4j</groupId><artifactId>docx4j-export-fo</artifactId><version>${docx4j.version}</version>
</dependency>

在word中插入${xxx},即可替换xxx内容
对应传递的map的key-val:xxx:替换内容
注:${ } 符号不可省略


import lombok.extern.slf4j.Slf4j;
import org.docx4j.Docx4J;
import org.docx4j.XmlUtils;
import org.docx4j.convert.out.FOSettings;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Document;
import org.springframework.util.CollectionUtils;import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Map;
import java.util.regex.Pattern;@Slf4j
public final class Docx4jUtils {/*** 替换变量并输出word文档* @param inputStream* @param map* @param outputStream*/public static void replaceDocUseDoc4j(InputStream inputStream, Map<String, String> map, OutputStream outputStream) {try {WordprocessingMLPackage doc = WordprocessingMLPackage.load(inputStream);MainDocumentPart mainDocumentPart = doc.getMainDocumentPart();if (!CollectionUtils.isEmpty(map)) {Docx4jUtils.cleanDocumentPart(mainDocumentPart);mainDocumentPart.variableReplace(map);}// 输出word文件doc.save(outputStream);outputStream.flush();} catch (Exception e) {log.error(e.getMessage(), e);}}/*** 替换变量并输出PDF文档* @param inputStream* @param map* @param outputStream* */public static void replaceDocOutputPDF(InputStream inputStream, Map<String, String> map,OutputStream outputStream) {try {WordprocessingMLPackage doc = WordprocessingMLPackage.load(inputStream);MainDocumentPart mainDocumentPart = doc.getMainDocumentPart();if (!CollectionUtils.isEmpty(map)) {Docx4jUtils.cleanDocumentPart(mainDocumentPart);mainDocumentPart.variableReplace(map);}setFontMapper(doc);FOSettings foSettings = Docx4J.createFOSettings();foSettings.setWmlPackage(doc);Docx4J.toFO(foSettings, outputStream, Docx4J.FLAG_EXPORT_PREFER_XSL);outputStream.flush();} catch (Exception e) {log.error(e.getMessage(), e);}}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("FangSong"));fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));fontMapper.put("等线", PhysicalFonts.get("SimSun"));fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));fontMapper.put("宋体扩展",PhysicalFonts.get("simsun-extB"));fontMapper.put("仿宋_GB2312",PhysicalFonts.get("FangSong_GB2312"));fontMapper.put("新細明體",PhysicalFonts.get("SimSun"));//解决宋体(正文)和宋体(标题)的乱码问题PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));mlPackage.setFontMapper(fontMapper);}public static boolean cleanDocumentPart(MainDocumentPart documentPart) throws Exception {if (documentPart == null) return false;Document document = documentPart.getContents();String wmlTemplate = XmlUtils.marshaltoString(document, true, false, Context.jc);document = (Document) XmlUtils.unwrap(DocxVariableClearUtils.doCleanDocumentPart(wmlTemplate, Context.jc));documentPart.setContents(document);return true;}private static class DocxVariableClearUtils {/*** 去任意XML标签*/private static final Pattern XML_PATTERN = Pattern.compile("<[^>]*>");private DocxVariableClearUtils() { }/*** start符号*/private static final char PREFIX = '$';/*** 中包含*/private static final char LEFT_BRACE = '{';/*** 结尾*/private static final char RIGHT_BRACE = '}';/*** 未开始*/private static final int NONE_START = -1;/*** 未开始*/private static final int NONE_START_INDEX = -1;/*** 开始*/private static final int PREFIX_STATUS = 1;/*** 左括号*/private static final int LEFT_BRACE_STATUS = 2;/*** 右括号*/private static final int RIGHT_BRACE_STATUS = 3;/*** doCleanDocumentPart** @param wmlTemplate* @param jc* @return* @throws JAXBException*/private static Object doCleanDocumentPart(String wmlTemplate, JAXBContext jc) throws JAXBException {// 进入变量块位置int curStatus = NONE_START;// 开始位置int keyStartIndex = NONE_START_INDEX;// 当前位置int curIndex = 0;char[] textCharacters = wmlTemplate.toCharArray();StringBuilder documentBuilder = new StringBuilder(textCharacters.length);documentBuilder.append(textCharacters);// 新文档StringBuilder newDocumentBuilder = new StringBuilder(textCharacters.length);// 最后一次写位置int lastWriteIndex = 0;for (char c : textCharacters) {switch (c) {case PREFIX:// TODO 不管其何状态直接修改指针,这也意味着变量名称里面不能有PREFIXkeyStartIndex = curIndex;curStatus = PREFIX_STATUS;break;case LEFT_BRACE:if (curStatus == PREFIX_STATUS) {curStatus = LEFT_BRACE_STATUS;}break;case RIGHT_BRACE:if (curStatus == LEFT_BRACE_STATUS) {// 接上之前的字符newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex, keyStartIndex));// 结束位置int keyEndIndex = curIndex + 1;// 替换String rawKey = documentBuilder.substring(keyStartIndex, keyEndIndex);// 干掉多余标签String mappingKey = XML_PATTERN.matcher(rawKey).replaceAll("");if (!mappingKey.equals(rawKey)) {char[] rawKeyChars = rawKey.toCharArray();// 保留原格式StringBuilder rawStringBuilder = new StringBuilder(rawKey.length());// 去掉变量引用字符for (char rawChar : rawKeyChars) {if (rawChar == PREFIX || rawChar == LEFT_BRACE || rawChar == RIGHT_BRACE) {continue;}rawStringBuilder.append(rawChar);}// FIXME 要求变量连在一起String variable = mappingKey.substring(2, mappingKey.length() - 1);int variableStart = rawStringBuilder.indexOf(variable);if (variableStart > 0) {rawStringBuilder = rawStringBuilder.replace(variableStart, variableStart + variable.length(), mappingKey);}newDocumentBuilder.append(rawStringBuilder.toString());} else {newDocumentBuilder.append(mappingKey);}lastWriteIndex = keyEndIndex;curStatus = NONE_START;keyStartIndex = NONE_START_INDEX;}default: break;}curIndex++;}// 余部if (lastWriteIndex < documentBuilder.length())newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex));return XmlUtils.unmarshalString(newDocumentBuilder.toString(), jc);}}
}

使用docx4j在线word转换pdf及替换文本域相关推荐

  1. 使用LibreOffice在线word转换pdf

    相关资料 Windows安装包:LibreOffice_7.0.6_Win_x64.msi Linux(CentOs)安装包:LibreOffice_7.0.6_Linux_x86-64_rpm.zi ...

  2. 【已解决】Word转换PDF时自动更新域导致图片表格的引用编号全部乱掉

    问题背景 最近在排版毕业设计,因为有很多图片和表格,为了省事,直接在文中引用图片,表格,就不用编号了,(这个时候文章的一级标题是'第1章'),但是学校要求一级标题的格式为"第一章" ...

  3. html5把word转为pDF,在线word转pdf 如何将word转换成pdf

    日常办公常接触到pdf.word文件,在打印或发送文件时也有需要word转成稳定性较好的pdf,那 一起来看看是如何将word转换成pdf的吧.打开安装好的word to pdf软件,如下图,界面很简 ...

  4. 免费!在线WORD转PDF的方法分享

    为什么一般会把WORD文档转成PDF呢?那是因为PDF便于查阅,兼容性.占用内存大小都比Word更好.所以大部分文件格式会使用PDF格式传输,今天就和大家分享一个在线WORD转PDF的方法,并且是有免 ...

  5. JAVA 使用 com.aspose.words将word转换PDF等

    因为公司前端需要在线查看word和PDF,后台上传需求将word等文件转换为PDF,原本使用的是liboffice进行转换,后来部署到服务器端之后,发现并不是很适合,由此找到com.aspose.wo ...

  6. Linux系统Word转换PDF,文档字体乱码不显示问题解决。

    1.问题 在Windows系统中,使用Java将Word文档转换为PDF格式时,结果文档内容正常:但是在Linux系统中,转出来PDF文档出现乱码或###符号等. 2.问题原因 这个问题是由于Linu ...

  7. 关于poi操作word,word转换pdf预览,这边文章就够了

    最近公司一个项目中需要导出一个简历word版,对于实习生的我开始是无从下手的,后来通过搜索发现可以使用poi来操作. 话不多说,先引入依赖 <dependency><groupId& ...

  8. Java WORD转换PDF 并添加水印 (附赠jar提取链接)

    Java WORD转换PDF 并添加水印 直接上代码 实现功能 docx文档转换为PDF 转换之后排版不混乱 使用工具(Jar包) aspose-words-15.8.0-jdk16.jar(用于PD ...

  9. Java使用aopse实现word转换pdf

    Java使用aopse实现word转换pdf 需要引用aspose包,引入操作我写了一个博客,地址如下 https://blog.csdn.net/weixin_46713508/article/de ...

  10. 解决 linux(centos7)word转换pdf时,pdf乱码问题

    本文解决当word转换为pdf时,pdf文档中的中文字体全部都是乱码(方框)的问题. 先简单的写一下word转换pdf的代码,这个网上有很多(最下方有引用一遍博客详细的讲解了如何转换) /**** @ ...

最新文章

  1. vue.js 源代码学习笔记 ----- 工具方法 lang
  2. java list 两个集合比较 不存在则新增 存在修改_Java之集合
  3. python入门经典例题-Python入门练习题(适合Python初学者做的练习题)
  4. 删除所有的.svn文件夹
  5. centos nfs java_CentOS下安装配置NFS并通过Java进行文件上传下载
  6. MySQL笔记(六)视图 view
  7. Uva1343-The Rotation Game-IDA*算法
  8. C++回调函数作为通信机制
  9. 什么叫ServletContext对象?
  10. FL Studio软件隐藏优惠码分享,音乐制作必备,创作无限可能!
  11. 三调数据库标注插件v1.2
  12. 迪普交换机恢复出厂设置_【迪普科技官网介绍】迪普科技交换机、防火墙_迪普科技(中国)公司简介-ZOL中关村在线厂商频道...
  13. 设计模式之责任链模式(Java实现)
  14. 影视作品(电影,电视剧,PV,MAD,AMV)的制作程序
  15. idea--Preferences
  16. sqlyog错误号码2058解决方式
  17. 怎么使用outlook发送邮件?outlook群发邮件怎么撤回?
  18. 批处理PS给相同图片添加不同文字
  19. java遍历变量_java – 循环遍历众多变量
  20. 没有扫描仪如何用PS把照片处理成扫描文件

热门文章

  1. MySQL数据库的恢复-mysql数据库的恢复
  2. mysql 命令行恢复数据库_使用MySQL命令行备份及恢复数据库
  3. SCADA和三大工业控制系统PLC、DCS、FCS
  4. matlab 2018 adams,关于ADAMS与MATLAB联合仿真的一点经验
  5. android 小米读写权限,Android 小米手机的权限问题
  6. java hashset retain_Java HashSet retainAll()用法及代码示例
  7. python画圆饼图
  8. 我的世界1.12.2java下载_我的世界1.12.2.2中文版下载 我的世界1.12.2.2中文版单机游戏下载...
  9. Magisk如何针对性隐藏Root避免被检测
  10. Java实现word转HTML