【随手记录】POI操作excel及word场景
最近有个需求,需要从多个excel表格源数据里读取内容,输出到word里,形式一份报告。以下是相关操作记录:
1、POM引用:
<!-- poi 操作word、excel、文档 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.2</version> </dependency>
2、需要从excel里读取内容有:单元格、表格、图表 这几类,于是定义以下规则:
1、${cell,s2,12,27} 获取excel第二个sheet的 12,27单元格值 2、${table,s2,1,3,4,32} 获取excel第二个sheet的 1,3 到 4,32处表格内容 3、${chart,s2,2} 获取exc第二个sheet的第二个图表数据 4、 运算符,如加、减、乘、除 这种放到里面最后面,${cell,s5,6,8,/10000}
3、读取word和excel数据源
4、遍历word模板,获取段落、表格、图表对象,分别执行替换
// 获取段落 doc.getParagraphs() // 获取表格 doc.getTables(); // 获取图表 doc..getCharts()
4.1、段落文本替换
通过XWPFParagraph段落对象,获取XWPFRun对象,XWPFRun为段落内一段文字,这里最坑的是目标字符${cell,s2,12,27}会因为在word里多次操作而拆分为多个XWPFRun,
这里采取XWPFParagraph.getText()方法,获取完整段落,判断段落里有没有目标字符,如果有,通过遍历XWPFParagraph包含的XWPFRun,如果XWPFRun包含$,则寻找${cell,s2,12,27}等目标操作符,直到遇到结束符}后,拼接为一个完整目标操作符,通过XWPFRun对象可以替换word模板内容 XWPFRun.setText("xx", 0);
4.2、处理table表格
遇到table对象,则通过遍历循环,获取每一个单元格值,填充到word模板里
List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs(); if (paragraphs != null && paragraphs.size() > 0) { for (XWPFParagraph paragraph : paragraphs) { List<XWPFRun> runs = paragraph.getRuns(); if (runs != null && runs.size() > 0) { for (XWPFRun run : runs) { run.setText("", 0); } } } // run可以设定字体,cell不行 XWPFRun run = paragraphs.get(0).createRun(); run.setFontSize(11); run.setText(cellExcelTxt); } else { XWPFRun run = xwpfTableCell.addParagraph().createRun(); run.setFontSize(11); run.setText(cellExcelTxt); }
如果直接在word通过POI创建XWPFTable对象,则会出现有一栏多余空白列,需要在word输出前删除掉
4.3、处理chart图表
一开始想从excel把chart输出为图片,然后保存到word里,但是找了一圈发现poi不支持把chart导出为图片,后来发现XSSFChart、XWPFChart对象继承同一个抽象类XDDFChart,可以直接通过以下方法
xwpfCharts.get(chartNumInWord++).importContent(chart);
直接从excel把图表复制到word
for (int i = 0; i < xwpfCharts.size(); i++) { XWPFChart xwpfChart = xwpfCharts.get(i);
//针对XWPFChart 在word里面无序的情况,可以通过名称里面的序号排序 String partName = xwpfChart.getPackagePart().getPartName().toString(); if (partName != null && partName.contains("chart" + (chartNumInWord))) { xwpfChart.importContent(chart); break; } }
如果world里排序还是无效,可以给图表加个标题,通过标题唯一性,建立映射关系
CTChart chartData = xwpfChart.getCTChart(); if (chartData != null && chartData.isSetTitle()) { CTTitle title = chartData.getTitle(); if (title != null && title.isSetTx() && title.getTx().isSetRich()) { String partName = title.getTx().getRich().getPArray(0).getRArray(0).getT(); // 编号比较 if (partName != null && partName.equals("chart" + (chartNumInWord + 1))) { xwpfChart.importContent(chart); } } }
5、除此之外,通过XWPFDocument还可以获取以下信息:
.getAllPictures() //获取图片 .getComments() //获取批注 .getEndnotes() //获取尾注 .getHeaderList() //获取页头 .getStyles() //获取风格设置 .getFooterList() //获取页脚
POIXMLProperties poixmlProperties = doc.getProperties();
POIXMLProperties.CoreProperties coreProperties = poixmlProperties.getCoreProperties();
coreProperties.getCategory(); //分类
coreProperties.getCreator(); //创建者,Microsoft Office User
coreProperties.getCreated(); //创建时间
coreProperties.getTitle(); //标题