【随手记录】POI操作excel及word场景
最近有个需求,需要从多个excel表格源数据里读取内容,输出到word里,形式一份报告。以下是相关操作记录:
1、POM引用:
1 2 3 4 5 6 7 8 9 10 11 | <!-- 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 2 3 4 | 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模板,获取段落、表格、图表对象,分别执行替换
1 2 3 4 5 6 | // 获取段落 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模板里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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,可以直接通过以下方法
1 | xwpfCharts.get(chartNumInWord++).importContent(chart); |
直接从excel把图表复制到word
1 2 3 4 5 6 7 8 | for ( int i = 0; i < xwpfCharts.size(); i++) { XWPFChart xwpfChart = xwpfCharts. get (i);<br> //针对XWPFChart 在word里面无序的情况,可以通过名称里面的序号排序 String partName = xwpfChart.getPackagePart().getPartName().toString(); if (partName != null && partName.contains( "chart" + (chartNumInWord))) { xwpfChart.importContent(chart); break ; } } |
如果world里排序还是无效,可以给图表加个标题,通过标题唯一性,建立映射关系
1 2 3 4 5 6 7 8 9 10 11 | 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还可以获取以下信息:
1 2 3 4 5 6 | .getAllPictures() //获取图片 .getComments() //获取批注 .getEndnotes() //获取尾注 .getHeaderList() //获取页头 .getStyles() //获取风格设置 .getFooterList() //获取页脚<br><br>POIXMLProperties poixmlProperties = doc.getProperties();<br>POIXMLProperties.CoreProperties coreProperties = poixmlProperties.getCoreProperties();<br>coreProperties.getCategory(); //分类<br>coreProperties.getCreator(); //创建者,Microsoft Office User<br>coreProperties.getCreated(); //创建时间<br>coreProperties.getTitle(); //标题 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探