【随手记录】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(); //标题

浙公网安备 33010602011771号