使用docx4j在线word转换pdf及替换文本域
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及替换文本域相关推荐
- 使用LibreOffice在线word转换pdf
相关资料 Windows安装包:LibreOffice_7.0.6_Win_x64.msi Linux(CentOs)安装包:LibreOffice_7.0.6_Linux_x86-64_rpm.zi ...
- 【已解决】Word转换PDF时自动更新域导致图片表格的引用编号全部乱掉
问题背景 最近在排版毕业设计,因为有很多图片和表格,为了省事,直接在文中引用图片,表格,就不用编号了,(这个时候文章的一级标题是'第1章'),但是学校要求一级标题的格式为"第一章" ...
- html5把word转为pDF,在线word转pdf 如何将word转换成pdf
日常办公常接触到pdf.word文件,在打印或发送文件时也有需要word转成稳定性较好的pdf,那 一起来看看是如何将word转换成pdf的吧.打开安装好的word to pdf软件,如下图,界面很简 ...
- 免费!在线WORD转PDF的方法分享
为什么一般会把WORD文档转成PDF呢?那是因为PDF便于查阅,兼容性.占用内存大小都比Word更好.所以大部分文件格式会使用PDF格式传输,今天就和大家分享一个在线WORD转PDF的方法,并且是有免 ...
- JAVA 使用 com.aspose.words将word转换PDF等
因为公司前端需要在线查看word和PDF,后台上传需求将word等文件转换为PDF,原本使用的是liboffice进行转换,后来部署到服务器端之后,发现并不是很适合,由此找到com.aspose.wo ...
- Linux系统Word转换PDF,文档字体乱码不显示问题解决。
1.问题 在Windows系统中,使用Java将Word文档转换为PDF格式时,结果文档内容正常:但是在Linux系统中,转出来PDF文档出现乱码或###符号等. 2.问题原因 这个问题是由于Linu ...
- 关于poi操作word,word转换pdf预览,这边文章就够了
最近公司一个项目中需要导出一个简历word版,对于实习生的我开始是无从下手的,后来通过搜索发现可以使用poi来操作. 话不多说,先引入依赖 <dependency><groupId& ...
- Java WORD转换PDF 并添加水印 (附赠jar提取链接)
Java WORD转换PDF 并添加水印 直接上代码 实现功能 docx文档转换为PDF 转换之后排版不混乱 使用工具(Jar包) aspose-words-15.8.0-jdk16.jar(用于PD ...
- Java使用aopse实现word转换pdf
Java使用aopse实现word转换pdf 需要引用aspose包,引入操作我写了一个博客,地址如下 https://blog.csdn.net/weixin_46713508/article/de ...
- 解决 linux(centos7)word转换pdf时,pdf乱码问题
本文解决当word转换为pdf时,pdf文档中的中文字体全部都是乱码(方框)的问题. 先简单的写一下word转换pdf的代码,这个网上有很多(最下方有引用一遍博客详细的讲解了如何转换) /**** @ ...
最新文章
- vue.js 源代码学习笔记 ----- 工具方法 lang
- java list 两个集合比较 不存在则新增 存在修改_Java之集合
- python入门经典例题-Python入门练习题(适合Python初学者做的练习题)
- 删除所有的.svn文件夹
- centos nfs java_CentOS下安装配置NFS并通过Java进行文件上传下载
- MySQL笔记(六)视图 view
- Uva1343-The Rotation Game-IDA*算法
- C++回调函数作为通信机制
- 什么叫ServletContext对象?
- FL Studio软件隐藏优惠码分享,音乐制作必备,创作无限可能!
- 三调数据库标注插件v1.2
- 迪普交换机恢复出厂设置_【迪普科技官网介绍】迪普科技交换机、防火墙_迪普科技(中国)公司简介-ZOL中关村在线厂商频道...
- 设计模式之责任链模式(Java实现)
- 影视作品(电影,电视剧,PV,MAD,AMV)的制作程序
- idea--Preferences
- sqlyog错误号码2058解决方式
- 怎么使用outlook发送邮件?outlook群发邮件怎么撤回?
- 批处理PS给相同图片添加不同文字
- java遍历变量_java – 循环遍历众多变量
- 没有扫描仪如何用PS把照片处理成扫描文件
热门文章
- MySQL数据库的恢复-mysql数据库的恢复
- mysql 命令行恢复数据库_使用MySQL命令行备份及恢复数据库
- SCADA和三大工业控制系统PLC、DCS、FCS
- matlab 2018 adams,关于ADAMS与MATLAB联合仿真的一点经验
- android 小米读写权限,Android 小米手机的权限问题
- java hashset retain_Java HashSet retainAll()用法及代码示例
- python画圆饼图
- 我的世界1.12.2java下载_我的世界1.12.2.2中文版下载 我的世界1.12.2.2中文版单机游戏下载...
- Magisk如何针对性隐藏Root避免被检测
- Java实现word转HTML