最近有个需求,就是要根据用户订单信息来填充现有的Word模版,从而生成一个在线电子文档,再通过易企签来实现线上签字确认 。
我们先来看看模版

这是我们项目上的大概文档,因为要涉及到一些文字替换和段落删减,引入了一些符号替换规则 。
POI操作Word的常用属性
在操作之前,我们需要了解一下属性和方法- XWPFDocument:用来获取或者创建一个Word文档
- XWPFParagraph:标题、文档、表格等
- XWPFRun:同样风格的一段文本
- XWPFTable:表格
- XWPFTableRow:表格中的一行
- XWPFTableCell:表格中的一个单元格
填充Word模版
现在我们就开始实践-填充我们上面的模版引入POI包
org.apache.poi poi${poi.version} org.apache.poi poi-ooxml${poi.version} 这里的变量值是
4.1.0 。
获取文档对象
由于我的文档模版是存储在GridFS中(其实我更倾向于MinIO),所以我的通过文件流的形式读取//通过文件读取XWPFDocument document = new XWPFDocument(OPCPackage.open(filePath));//通过文件流读取,in是InputStream对象XWPFDocument document = new XWPFDocument(in);获取到文档之后,就可以从中获取到对应的XWPFParagraph对象
List paragraphs = document.getParagraphs(); 让后我们可以从XWPFParagraph获取到Text即段落中的内容 , 但是我们要替换段落中的内容的话必须在XWPFRun才行 。所以需要循环遍历去处理
for (XWPFParagraph paragraph : paragraphs) {List runs = paragraph.getRuns();for (XWPFRun run : runs) {}} 这里我们可以通过run.toString()获取到内容 , 并通过run.setText进行替换 。在我们获取到文本之后,要匹配出对象的关键字,所以这里需要一个正则匹配
private static List getKeywords(String source) {String regStr = "\$\{[a-zA-Z0-9] \}";List matchStrs = new ArrayList<>();Pattern patten = Pattern.compile(regStr);Matcher matcher = patten.matcher(source);while (matcher.find()) {matchStrs.add(matcher.group());}return matchStrs;}我们通过getKeywords获取到模版中的关键字后,再从Map对象中去取出对应的值,然replace掉
【Java基于POI填充Word模版】
for (XWPFParagraph paragraph : paragraphs) {List runs = paragraph.getRuns();for (XWPFRun run : runs) {String value=https://www.itzhengshu.com/word/run.ToString();List keywords = getKeywords(value);for (String keyword : keywords) {String key = keyword.replace("${", "").replace("}", "");String keyValue = https://www.itzhengshu.com/word/sourceTextMap.get(key);if (StringUtils.isEmpty(keyValue)) {keyValue ="";}value = https://www.itzhengshu.com/word/value.replace(keyword, keyValue);}run.setText(value,0);} } 一般的内容可以通过${key}的方式来替换,那么遇到表格怎么办呢?我继续来处理表格
List tables = document.getTables(); 我这里先只针对我的模版进行处理 , 如果是遇到多个XWPFTable那么就根据情况自行处理吧
for (int i = 1; i < tableList.size(); i) {XWPFTableRow newRow = table.createRow();List cells = newRow.getTableCells();for (int j = 0; j < cells.size(); j) {XWPFTableCell cell = cells.get(j);cell.setText(tableList.get(i - 1)[j]);}}if (!ObjectUtils.isEmpty(tableBottom)) {XWPFTableRow tableRow = table.createRow();List footerCells = tableRow.getTableCells();for (int j = 0; j < footerCells.size(); j) {XWPFTableCell cell = footerCells.get(j);if (!StringUtils.isEmpty(tableBottom[j])) {XWPFParagraph paragraph = cell.addParagraph();XWPFRun xwpfRun = paragraph.createRun();xwpfRun.setText(tableBottom[j]);xwpfRun.setFontSize(12);xwpfRun.setFontFamily("黑体");xwpfRun.setBold(true);xwpfRun.setColor("000000");} else {cell.setText(tableBottom[j]);}}} 这里就会根据我们的传入的tableList即表格数据进行填充 。根据tableBottom数组来添加一些样式 。最后来看看我们做出的效果 , 首先是用Swagger调用接口
{"fileName":"xxx订单导出.doc","filePath":"order_template.docx","headerContent":{"orderDate":"2020-03-26 10:25","planDate":"202-03-27","orderNo":"20200325000074645","agreeNo":"80192000035","orderUnitNo":"155283","orderUnitName":"小卖部农业开发有限公司","name":"IT界摸鱼专家","phone":"138888888","bankNo":"6666666666666666573","owe":"小鸡炖蘑菇有限公司开发区分公司","owePrice":"16775.90","zh":"壹万伍仟捌佰贰拾伍圆零角零分","isDiaplay":"","memo":"小鸡炖蘑菇专用配送"},"tableList":[["113029022","小鸡炖蘑菇了不起","2","T","50","2000.00","300000.00",""],["113029044","小鸡炖蘑菇真棒","1.5","T","75","3000.00","50000.00",""],["113029077","小鸡炖蘑菇好耶","1.275","T","85","2020.50","900000.50","赠品"],["113040057","小鸡炖蘑菇","10.025","T","255","12030.00","200000.20",""]],"tableBottom":["合计","壹万伍仟捌佰贰拾伍圆整","55.275","","852","","2255114.00","60.32T"]}上面是我传参数,最后导出的Word文档是这样的

当然 , 这里还有一些细节需要处理 。
