最近有个需求,就是要根据用户订单信息来填充现有的Word模版,从而生成一个在线电子文档,再通过易企签来实现线上签字确认。
我们先来看看模板
![](http://dingyue.ws.126.net/2020/1022/6c4210efj00qilxbj0083c0013o00p4m.jpg)
这是我们项目上的大概文档,因为要涉及到一些文字替换和段落删减,引入了一些符号替换规则。
POI操作Word的常用属性
在操作之前,我们需要了解一下属性和方法
- XWPFDocument:用来获取或者创建一个Word文档
- XWPFParagraph:标题、文档、表格等
- XWPFRun:同样风格的一段文本
- XWPFTable:表格
- XWPFTableRow:表格中的一行
- XWPFTableCell:表格中的一个单元格
填充Word模版
现在我们就开始实践-填充我们上面的模版
引入POI包
org.apache.poigroupId>poiartifactId>${poi.version}version>dependency>org.apache.poigroupId>poi-ooxmlartifactId>${poi.version}version>dependency>
这里的变量值是。
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掉
for (XWPFParagraph paragraph : paragraphs) { List
runs = paragraph.getRuns(); for (XWPFRun run : runs) { String value=run.ToString(); List
keywords = getKeywords(value); for (String keyword : keywords ) { String key = keyword.replace("${", "").replace("}", ""); String keyValue = sourceTextMap.get(key); if (StringUtils.isEmpty(keyValue)) { keyValue = ""; } value = 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文档是这样的
![](http://dingyue.ws.126.net/2020/1022/a5f505c2j00qilxbj00cmc0013y00yam.jpg)
当然,这里还有一些细节需要处理。
热门跟贴