java使用poi在word中生成柱状图、折线图、饼图、柱状图+折线图组合图、动态表格、文本替换、图片替换、更新内置Excel数据、更新插入的文本框内容、合并表格单元格; 您所在的位置:网站首页 word画折线图xy轴名字 java使用poi在word中生成柱状图、折线图、饼图、柱状图+折线图组合图、动态表格、文本替换、图片替换、更新内置Excel数据、更新插入的文本框内容、合并表格单元格;

java使用poi在word中生成柱状图、折线图、饼图、柱状图+折线图组合图、动态表格、文本替换、图片替换、更新内置Excel数据、更新插入的文本框内容、合并表格单元格;

2024-03-25 11:53| 来源: 网络整理| 查看: 265

本文参考地址:poi在Word中生成各种图表(支持柱状、组合、环状图、折线图、等常用图)_poi word 图表_wangxiaoyingWXY的博客-CSDN博客 在参考文章的基础上,增加了扩展。感谢被参考的妹子。另外该博客主要记录很多poi操作word中遇到的问题和解决方式,所以会一直维护下去。

另外,我是在本地使用的wps,使用office的老哥(老姐)们可能在效果上有出入。

本文只是简单示例,仅做代码参考,在实际运用中可自行根据业务封装。

模板在示例代码中有的哈,在resource目录下面 模板在示例代码中有的哈,在resource目录下面 模板在示例代码中有的哈,在resource目录下面

还有就是博主真的很菜.....(手动滑稽)

关于示例代码:(码云地址)poi-demo: poi使用demo,主要用于word生成各种图表元素

另外如果遇到模板标签不完整的情况,请参考:poi 读取word模板,确保 {{参数名}} 在一个XWPFRun_… …的博客-CSDN博客

说明:在poi3.x的版本中,没有对图表的支持,至少目前为止没有找到相应的文章介绍;在poi4.x的版本中加入了对图表的支持,所以需要引入poi4.x的依赖包,并且JDK最低版本要求8;

2019-12-04:新增:动态刷新内置Excel数据

2020-04-07:新增:更新插入的文本框内容(感谢博友:输过败过但不曾怕过啊)

2020-04-10:新增:新增一个定位图表的方式(感谢博友:输过败过但不曾怕过啊)

2020-04-11:新增:柱状图动态列,优化修改(兼容wps和office)(感谢:谈个长长的恋爱可好)

2020-04-21:新增:表格进行合并单元格,横竖都行,两种方式(感谢刘老师)

2020-04-23:解决问题:组合图页面显示的数据,跟第二列对应不上(感谢博友:吹古拉朽)

2020-06-06:解决问题:图表设置系列标题方式错误导致office无法打开的问题(感谢博友: qq_18900373)

// 设置标题 CTSerTx tx = ser.getTx(); tx.setV("阿里嘎痛"); // wps可以打开,office无法打开 tx.getStrRef().getStrCache().getPtList().get(0).setV("阿里嘎痛"); // wps和office都能打开

1.引入maven依赖包

org.apache.poi poi 4.1.0 org.apache.poi poi-ooxml 4.1.0

完整pom.xml内容

4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.8.RELEASE com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.apache.poi poi 4.1.0 org.apache.poi poi-ooxml 4.1.0 org.springframework.boot spring-boot-maven-plugin

2.准备word模板文件,注意后缀是docx,模板中的图表可以有数据,但是最终会被代码替换,所以不重要

模板文件: 不知道怎么上传了,需要的私信吧,感谢;

3.两个类

类1:PoiDemoWordTable 

package com.example.demo; import com.example.demo.util.PoiWordTools; import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.util.Units; import org.apache.poi.xwpf.usermodel.*; import org.apache.xmlbeans.XmlCursor; import org.springframework.util.StringUtils; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class PoiDemoWordTable { public static void main(String[] args) throws Exception { final String returnurl = "D:\\youxi\\jx\\result.docx"; // 结果文件 final String templateurl = "D:\\youxi\\jx\\test.docx"; // 模板文件 InputStream is = new FileInputStream(new File(templateurl)); XWPFDocument doc = new XWPFDocument(is); // 替换word模板数据 replaceAll(doc); // 保存结果文件 try { File file = new File(returnurl); if (file.exists()) { file.delete(); } FileOutputStream fos = new FileOutputStream(returnurl); doc.write(fos); fos.close(); } catch (Exception e) { e.printStackTrace(); } } /** * @Description: 替换段落和表格中 */ public static void replaceAll(XWPFDocument doc) throws InvalidFormatException, IOException { doParagraphs(doc); // 处理段落文字数据,包括文字和表格、图片 doCharts(doc); // 处理图表数据,柱状图、折线图、饼图啊之类的 } /** * 处理段落文字 * * @param doc * @throws InvalidFormatException * @throws FileNotFoundException * @throws IOException */ public static void doParagraphs(XWPFDocument doc) throws InvalidFormatException, IOException { // 文本数据 Map textMap = new HashMap(); textMap.put("var", "我是被替换的文本内容"); // 图片数据 Map imgMap = new HashMap(); imgMap.put("img", "D:/youxi/ddd.png"); /**----------------------------处理段落------------------------------------**/ List paragraphList = doc.getParagraphs(); if (paragraphList != null && paragraphList.size() > 0) { for (XWPFParagraph paragraph : paragraphList) { List runs = paragraph.getRuns(); for (XWPFRun run : runs) { String text = run.getText(0); if (text != null) { // 替换文本信息 String tempText = text; String key = tempText.replaceAll("\\{\\{", "").replaceAll("}}", ""); if (!StringUtils.isEmpty(textMap.get(key))) { run.setText(textMap.get(key), 0); } // 替换图片内容 参考:https://blog.csdn.net/a909301740/article/details/84984445 String tempImgText = text; String imgkey = tempImgText.replaceAll("\\{\\{@", "").replaceAll("}}", ""); if (!StringUtils.isEmpty(imgMap.get(imgkey))) { String imgPath = imgMap.get(imgkey); try { run.setText("", 0); run.addPicture(new FileInputStream(imgPath), Document.PICTURE_TYPE_PNG, "img.png", Units.toEMU(200), Units.toEMU(200)); } catch (Exception e) { e.printStackTrace(); } } // 动态表格 if (text.contains("${table1}")) { run.setText("", 0); XmlCursor cursor = paragraph.getCTP().newCursor(); XWPFTable tableOne = doc.insertNewTbl(cursor);// ---这个是关键 // 设置表格宽度,第一行宽度就可以了,这个值的单位,目前我也还不清楚,还没来得及研究 tableOne.setWidth(8500); // 表格第一行,对于每个列,必须使用createCell(),而不是getCell(),因为第一行嘛,肯定是属于创建的,没有create哪里来的get呢 XWPFTableRow tableOneRowOne = tableOne.getRow(0);//行 new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "序号"); new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(英文)"); new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(中文)"); // 表格第二行 XWPFTableRow tableOneRowTwo = tableOne.createRow();//行 new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "一行一列"); new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(1), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "一行一列"); new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(2), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "一行一列"); // ....... 可动态添加表格 } } } } } } /** * 处理图表 * * @param doc * @throws FileNotFoundException */ public static void doCharts(XWPFDocument doc) throws FileNotFoundException { /**----------------------------处理图表------------------------------------**/ // 数据准备 List titleArr = new ArrayList();// 标题 titleArr.add("title"); titleArr.add("金额"); List fldNameArr = new ArrayList();// 字段名 fldNameArr.add("item1"); fldNameArr.add("item2"); // 数据集合 List listItemsByType = new ArrayList(); // 第一行数据 Map base1 = new HashMap(); base1.put("item1", "材料费用"); base1.put("item2", "500"); // 第二行数据 Map base2 = new HashMap(); base2.put("item1", "出差费用"); base2.put("item2", "300"); // 第三行数据 Map base3 = new HashMap(); base3.put("item1", "住宿费用"); base3.put("item2", "300"); listItemsByType.add(base1); listItemsByType.add(base2); listItemsByType.add(base3); // 获取word模板中的所有图表元素,用map存放 // 为什么不用list保存:查看doc.getRelations()的源码可知,源码中使用了hashMap读取文档图表元素, // 对relations变量进行打印后发现,图表顺序和文档中的顺序不一致,也就是说relations的图表顺序不是文档中从上到下的顺序 Map chartsMap = new HashMap(); //动态刷新图表 List relations = doc.getRelations(); for (POIXMLDocumentPart poixmlDocumentPart : relations) { if (poixmlDocumentPart instanceof XWPFChart) { // 如果是图表元素 String str = poixmlDocumentPart.toString(); System.out.println("str:" + str); String key = str.replaceAll("Name: ", "") .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "").trim(); System.out.println("key:" + key); chartsMap.put(key, poixmlDocumentPart); } } System.out.println("\n图表数量:" + chartsMap.size() + "\n"); // 第一个图表-条形图 POIXMLDocumentPart poixmlDocumentPart0 = chartsMap.get("/word/charts/chart1.xml"); new PoiWordTools().replaceBarCharts(poixmlDocumentPart0, titleArr, fldNameArr, listItemsByType); // 第二个-柱状图 POIXMLDocumentPart poixmlDocumentPart1 = chartsMap.get("/word/charts/chart2.xml"); new PoiWordTools().replaceBarCharts(poixmlDocumentPart1, titleArr, fldNameArr, listItemsByType); // 第三个图表-多列柱状图 doCharts3(chartsMap); // 第四个图表-折线图 doCharts4(chartsMap); // 第五个图表-饼图 POIXMLDocumentPart poixmlDocumentPart4 = chartsMap.get("/word/charts/chart5.xml"); new PoiWordTools().replacePieCharts(poixmlDocumentPart4, titleArr, fldNameArr, listItemsByType); doCharts6(chartsMap); } public static void doCharts3(Map chartsMap) { // 数据准备 List titleArr = new ArrayList();// 标题 titleArr.add("姓名"); titleArr.add("欠款"); titleArr.add("存款"); List fldNameArr = new ArrayList();// 字段名 fldNameArr.add("item1"); fldNameArr.add("item2"); fldNameArr.add("item3"); // 数据集合 List listItemsByType = new ArrayList(); // 第一行数据 Map base1 = new HashMap(); base1.put("item1", "老张"); base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第二行数据 Map base2 = new HashMap(); base2.put("item1", "老李"); base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第三行数据 Map base3 = new HashMap(); base3.put("item1", "老刘"); base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); listItemsByType.add(base1); listItemsByType.add(base2); listItemsByType.add(base3); POIXMLDocumentPart poixmlDocumentPart2 = chartsMap.get("/word/charts/chart3.xml"); new PoiWordTools().replaceBarCharts(poixmlDocumentPart2, titleArr, fldNameArr, listItemsByType); } public static void doCharts4(Map chartsMap) { // 数据准备 List titleArr = new ArrayList();// 标题 titleArr.add("title"); titleArr.add("占基金资产净值比例22222(%)"); titleArr.add("额外的(%)"); titleArr.add("额外的(%)"); List fldNameArr = new ArrayList();// 字段名 fldNameArr.add("item1"); fldNameArr.add("item2"); fldNameArr.add("item3"); fldNameArr.add("item4"); // 数据集合 List listItemsByType = new ArrayList(); // 第一行数据 Map base1 = new HashMap(); base1.put("item1", "材料费用"); base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base1.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第二行数据 Map base2 = new HashMap(); base2.put("item1", "出差费用"); base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base2.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第三行数据 Map base3 = new HashMap(); base3.put("item1", "住宿费用"); base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base3.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); listItemsByType.add(base1); listItemsByType.add(base2); listItemsByType.add(base3); POIXMLDocumentPart poixmlDocumentPart2 = chartsMap.get("/word/charts/chart4.xml"); new PoiWordTools().replaceLineCharts(poixmlDocumentPart2, titleArr, fldNameArr, listItemsByType); } /** * 对应文档中的第6个图表(预处理—分公司情况) */ public static void doCharts6(Map chartsMap) { // 数据准备 List titleArr = new ArrayList();// 标题 titleArr.add("title"); titleArr.add("投诉受理量(次)"); titleArr.add("预处理拦截工单量(次)"); titleArr.add("拦截率"); List fldNameArr = new ArrayList();// 字段名 fldNameArr.add("item1"); fldNameArr.add("item2"); fldNameArr.add("item3"); fldNameArr.add("item4"); // 数据集合 List listItemsByType = new ArrayList(); // 第一行数据 Map base1 = new HashMap(); base1.put("item1", "通辽"); base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base1.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第二行数据 Map base2 = new HashMap(); base2.put("item1", "呼和浩特"); base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base2.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第三行数据 Map base3 = new HashMap(); base3.put("item1", "锡林郭勒"); base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base3.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第四行数据 Map base4 = new HashMap(); base4.put("item1", "阿拉善"); base4.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base4.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base4.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第五行数据 Map base5 = new HashMap(); base5.put("item1", "巴彦淖尔"); base5.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base5.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base5.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第六行数据 Map base6 = new HashMap(); base6.put("item1", "兴安"); base6.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base6.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base6.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第七行数据 Map base7 = new HashMap(); base7.put("item1", "乌兰察布"); base7.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base7.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base7.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第八行数据 Map base8 = new HashMap(); base8.put("item1", "乌海"); base8.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base8.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base8.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第九行数据 Map base9 = new HashMap(); base9.put("item1", "赤峰"); base9.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base9.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base9.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第十行数据 Map base10 = new HashMap(); base10.put("item1", "包头"); base10.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base10.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base10.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第十一行数据 Map base11 = new HashMap(); base11.put("item1", "呼伦贝尔"); base11.put("item2", (int)(int)(1 + Math.random() * (100 - 1 + 1)) + ""); base11.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base11.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); // 第十二行数据 Map base12 = new HashMap(); base12.put("item1", "鄂尔多斯"); base12.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base12.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); base12.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + ""); listItemsByType.add(base1); listItemsByType.add(base2); listItemsByType.add(base3); listItemsByType.add(base4); listItemsByType.add(base5); listItemsByType.add(base6); listItemsByType.add(base7); listItemsByType.add(base8); listItemsByType.add(base9); listItemsByType.add(base10); listItemsByType.add(base11); listItemsByType.add(base12); // 下标0的图表-折线图 POIXMLDocumentPart poixmlDocumentPart5 = chartsMap.get("/word/charts/chart6.xml"); new PoiWordTools().replaceCombinationCharts(poixmlDocumentPart5, titleArr, fldNameArr, listItemsByType); } }

类2:PoiWordTools

package com.example.demo.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.util.List; import java.util.Map; import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xwpf.usermodel.XWPFChart; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.openxmlformats.schemas.drawingml.x2006.chart.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTColor; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTParaRPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc; /** * poi生成word的工具类 * 针对于模板中的图表是静态的,也就是模板中的图表长什么样子不会根据数据而改变 */ public class PoiWordTools { private static final BigDecimal bd2 = new BigDecimal("2"); /** * 调用替换柱状图数据 */ public static void replaceBarCharts(POIXMLDocumentPart poixmlDocumentPart, List titleArr, List fldNameArr, List listItemsByType) { XWPFChart chart = (XWPFChart) poixmlDocumentPart; chart.getCTChart(); //根据属性第一列名称切换数据类型 CTChart ctChart = chart.getCTChart(); CTPlotArea plotArea = ctChart.getPlotArea(); CTBarChart barChart = plotArea.getBarChartArray(0); List BarSerList = barChart.getSerList(); // 获取柱状图单位 //刷新内置excel数据 new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr); //刷新页面显示数据 refreshBarStrGraphContent(barChart, BarSerList, listItemsByType, fldNameArr, 1); } /** * 调用替换折线图数据 */ public static void replaceLineCharts(POIXMLDocumentPart poixmlDocumentPart, List titleArr, List fldNameArr, List listItemsByType) { XWPFChart chart = (XWPFChart) poixmlDocumentPart; chart.getCTChart(); //根据属性第一列名称切换数据类型 CTChart ctChart = chart.getCTChart(); CTPlotArea plotArea = ctChart.getPlotArea(); CTLineChart lineChart = plotArea.getLineChartArray(0); List lineSerList = lineChart.getSerList(); // 获取折线图单位 //刷新内置excel数据 new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr); //刷新页面显示数据 new PoiWordTools().refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 1); } /** * 调用替换饼图数据 */ public static void replacePieCharts(POIXMLDocumentPart poixmlDocumentPart, List titleArr, List fldNameArr, List listItemsByType) { XWPFChart chart = (XWPFChart) poixmlDocumentPart; chart.getCTChart(); //根据属性第一列名称切换数据类型 CTChart ctChart = chart.getCTChart(); CTPlotArea plotArea = ctChart.getPlotArea(); CTPieChart pieChart = plotArea.getPieChartArray(0); List pieSerList = pieChart.getSerList(); // 获取饼图单位 //刷新内置excel数据 new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr); //刷新页面显示数据 new PoiWordTools().refreshPieStrGraphContent(pieChart, pieSerList, listItemsByType, fldNameArr, 1); } /** * 调用替换柱状图、折线图组合数据 */ public static void replaceCombinationCharts(POIXMLDocumentPart poixmlDocumentPart, List titleArr, List fldNameArr, List listItemsByType) { XWPFChart chart = (XWPFChart) poixmlDocumentPart; chart.getCTChart(); //根据属性第一列名称切换数据类型 CTChart ctChart = chart.getCTChart(); CTPlotArea plotArea = ctChart.getPlotArea(); CTBarChart barChart = plotArea.getBarChartArray(0); List barSerList = barChart.getSerList(); // 获取柱状图单位 //刷新内置excel数据 new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr); //刷新页面显示数据 数据中下标1开始的是柱状图数据,所以这个是1 refreshBarStrGraphContent(barChart, barSerList, listItemsByType, fldNameArr, 1); CTLineChart lineChart = plotArea.getLineChartArray(0); List lineSerList = lineChart.getSerList(); // 获取折线图单位 //刷新内置excel数据 有一个就可以了 有一个就可以了 有一个就可以了 //new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr); //刷新页面显示数据 数据中下标3开始的是折线图的数据,所以这个是3 new PoiWordTools().refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 3); } /** * 刷新折线图数据方法 * * @param typeChart * @param serList * @param dataList * @param fldNameArr * @param position * @return */ public static boolean refreshLineStrGraphContent(Object typeChart, List serList, List dataList, List fldNameArr, int position) { boolean result = true; //更新数据区域 for (int i = 0; i < serList.size(); i++) { //CTSerTx tx=null; CTAxDataSource cat = null; CTNumDataSource val = null; CTLineSer ser = ((CTLineChart) typeChart).getSerArray(i); //tx= ser.getTx(); // Category Axis Data cat = ser.getCat(); // 获取图表的值 val = ser.getVal(); // strData.set CTStrData strData = cat.getStrRef().getStrCache(); CTNumData numData = val.getNumRef().getNumCache(); strData.setPtArray((CTStrVal[]) null); // unset old axis text numData.setPtArray((CTNumVal[]) null); // unset old values // set model long idx = 0; for (int j = 0; j < dataList.size(); j++) { //判断获取的值是否为空 String value = "0"; if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) { value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString(); } if (!"0".equals(value)) { CTNumVal numVal = numData.addNewPt();//序列值 numVal.setIdx(idx); numVal.setV(value); } CTStrVal sVal = strData.addNewPt();//序列名称 sVal.setIdx(idx); sVal.setV(dataList.get(j).get(fldNameArr.get(0))); idx++; } numData.getPtCount().setVal(idx); strData.getPtCount().setVal(idx); //赋值横坐标数据区域 String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0) .formatAsString("Sheet1", false); cat.getStrRef().setF(axisDataRange); //数据区域 String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position) .formatAsString("Sheet1", false); val.getNumRef().setF(numDataRange); // 设置系列生成方向 } return result; } /** * 刷新柱状图数据方法 * * @param typeChart * @param serList * @param dataList * @param fldNameArr * @param position * @return */ public static boolean refreshBarStrGraphContent(Object typeChart, List serList, List dataList, List fldNameArr, int position) { boolean result = true; //更新数据区域 for (int i = 0; i < serList.size(); i++) { // CTSerTx tx=null; CTAxDataSource cat = null; CTNumDataSource val = null; CTBarSer ser = ((CTBarChart) typeChart).getSerArray(i); // tx= ser.getTx(); // Category Axis Data cat = ser.getCat(); // 获取图表的值 val = ser.getVal(); // strData.set CTStrData strData = cat.getStrRef().getStrCache(); CTNumData numData = val.getNumRef().getNumCache(); strData.setPtArray((CTStrVal[]) null); // unset old axis text numData.setPtArray((CTNumVal[]) null); // unset old values // set model long idx = 0; for (int j = 0; j < dataList.size(); j++) { //判断获取的值是否为空 String value = "0"; if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) { value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString(); } if (!"0".equals(value)) { CTNumVal numVal = numData.addNewPt();//序列值 numVal.setIdx(idx); numVal.setV(value); } CTStrVal sVal = strData.addNewPt();//序列名称 sVal.setIdx(idx); sVal.setV(dataList.get(j).get(fldNameArr.get(0))); idx++; } numData.getPtCount().setVal(idx); strData.getPtCount().setVal(idx); //赋值横坐标数据区域 String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0) .formatAsString("Sheet1", true); cat.getStrRef().setF(axisDataRange); //数据区域 String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position) .formatAsString("Sheet1", true); val.getNumRef().setF(numDataRange); } return result; } /** * 刷新饼图数据方法 * * @param typeChart * @param serList * @param dataList * @param fldNameArr * @param position * @return */ public static boolean refreshPieStrGraphContent(Object typeChart, List serList, List dataList, List fldNameArr, int position) { boolean result = true; //更新数据区域 for (int i = 0; i < serList.size(); i++) { //CTSerTx tx=null; CTAxDataSource cat = null; CTNumDataSource val = null; CTPieSer ser = ((CTPieChart) typeChart).getSerArray(i); //tx= ser.getTx(); // Category Axis Data cat = ser.getCat(); // 获取图表的值 val = ser.getVal(); // strData.set CTStrData strData = cat.getStrRef().getStrCache(); CTNumData numData = val.getNumRef().getNumCache(); strData.setPtArray((CTStrVal[]) null); // unset old axis text numData.setPtArray((CTNumVal[]) null); // unset old values // set model long idx = 0; for (int j = 0; j < dataList.size(); j++) { //判断获取的值是否为空 String value = "0"; if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) { value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString(); } if (!"0".equals(value)) { CTNumVal numVal = numData.addNewPt();//序列值 numVal.setIdx(idx); numVal.setV(value); } CTStrVal sVal = strData.addNewPt();//序列名称 sVal.setIdx(idx); sVal.setV(dataList.get(j).get(fldNameArr.get(0))); idx++; } numData.getPtCount().setVal(idx); strData.getPtCount().setVal(idx); //赋值横坐标数据区域 String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0) .formatAsString("Sheet1", true); cat.getStrRef().setF(axisDataRange); //数据区域 String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position) .formatAsString("Sheet1", true); val.getNumRef().setF(numDataRange); } return result; } /** * 刷新内置excel数据 * * @param chart * @param dataList * @param fldNameArr * @param titleArr * @return */ public static boolean refreshExcel(XWPFChart chart, List dataList, List fldNameArr, List titleArr) { boolean result = true; Workbook wb = new XSSFWorkbook(); Sheet sheet = wb.createSheet("Sheet1"); //根据数据创建excel第一行标题行 for (int i = 0; i < titleArr.size(); i++) { if (sheet.getRow(0) == null) { sheet.createRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i)); } else { sheet.getRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i)); } } //遍历数据行 for (int i = 0; i < dataList.size(); i++) { Map baseFormMap = dataList.get(i);//数据行 //fldNameArr字段属性 for (int j = 0; j < fldNameArr.size(); j++) { if (sheet.getRow(i + 1) == null) { if (j == 0) { try { sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)) == null ? "" : baseFormMap.get(fldNameArr.get(j))); } catch (Exception e) { if (baseFormMap.get(fldNameArr.get(j)) == null) { sheet.createRow(i + 1).createCell(j).setCellValue(""); } else { sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j))); } } } } else { BigDecimal b = new BigDecimal(baseFormMap.get(fldNameArr.get(j))); double value = 0d; if (b != null) { value = b.doubleValue(); } if (value == 0) { sheet.getRow(i + 1).createCell(j); } else { sheet.getRow(i + 1).createCell(j).setCellValue(b.doubleValue()); } } } } // 更新嵌入的workbook POIXMLDocumentPart xlsPart = chart.getRelations().get(0); OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream(); try { wb.write(xlsOut); xlsOut.close(); } catch (IOException e) { e.printStackTrace(); result = false; } finally { if (wb != null) { try { wb.close(); } catch (IOException e) { e.printStackTrace(); result = false; } } } return result; } /** * 设置表格样式 * * @param cell * @param fontName * @param fontSize * @param fontBlod * @param alignment * @param vertical * @param fontColor * @param bgColor * @param cellWidth * @param content */ public static void setWordCellSelfStyle(XWPFTableCell cell, String fontName, String fontSize, int fontBlod, String alignment, String vertical, String fontColor, String bgColor, String cellWidth, String content) { //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理 BigInteger bFontSize = new BigInteger("24"); if (fontSize != null && !fontSize.equals("")) { //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理 BigDecimal fontSizeBD = new BigDecimal(fontSize); fontSizeBD = bd2.multiply(fontSizeBD); fontSizeBD = fontSizeBD.setScale(0, BigDecimal.ROUND_HALF_UP);//这里取整 bFontSize = new BigInteger(fontSizeBD.toString());// 字体大小 } // 设置单元格宽度 cell.setWidth(cellWidth); //=====获取单元格 CTTc tc = cell.getCTTc(); //====tcPr开始====》》》》 CTTcPr tcPr = tc.getTcPr();//获取单元格里的 if (tcPr == null) {//没有,创建 tcPr = tc.addNewTcPr(); } // --vjc开始-->> CTVerticalJc vjc = tcPr.getVAlign();//获取 的 if (vjc == null) {//没有,创建 vjc = tcPr.addNewVAlign(); } //设置单元格对齐方式 vjc.setVal(vertical.equals("top") ? STVerticalJc.TOP : vertical.equals("bottom") ? STVerticalJc.BOTTOM : STVerticalJc.CENTER); //垂直对齐 CTShd shd = tcPr.getShd();//获取里的 if (shd == null) {//没有,创建 shd = tcPr.addNewShd(); } // 设置背景颜色 shd.setFill(bgColor.substring(1)); //《《《《====tcPr结束==== //====p开始====》》》》 CTP p = tc.getPList().get(0);//获取单元格里的 //---ppr开始--->>> CTPPr ppr = p.getPPr();//获取里的 if (ppr == null) {//没有,创建 ppr = p.addNewPPr(); } // --jc开始-->> CTJc jc = ppr.getJc();//获取里的 if (jc == null) {//没有,创建 jc = ppr.addNewJc(); } //设置单元格对齐方式 jc.setVal(alignment.equals("left") ? STJc.LEFT : alignment.equals("right") ? STJc.RIGHT : STJc.CENTER); //水平对齐 // CTParaRPr pRpr = ppr.getRPr(); //获取里的 if (pRpr == null) {//没有,创建 pRpr = ppr.addNewRPr(); } CTFonts pfont = pRpr.getRFonts();//获取里的 if (pfont == null) {//没有,创建 pfont = pRpr.addNewRFonts(); } //设置字体 pfont.setAscii(fontName); pfont.setEastAsia(fontName); pfont.setHAnsi(fontName); CTOnOff pb = pRpr.getB();//获取里的 if (pb == null) {//没有,创建 pb = pRpr.addNewB(); } //设置字体是否加粗 pb.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF); CTHpsMeasure psz = pRpr.getSz();//获取里的 if (psz == null) {//没有,创建 psz = pRpr.addNewSz(); } // 设置单元格字体大小 psz.setVal(bFontSize); CTHpsMeasure pszCs = pRpr.getSzCs();//获取里的 if (pszCs == null) {//没有,创建 pszCs = pRpr.addNewSzCs(); } // 设置单元格字体大小 pszCs.setVal(bFontSize); // > CTRPr rpr = r.getRPr();//获取里的 if (rpr == null) {//没有,创建 rpr = r.addNewRPr(); } //->- CTFonts font = rpr.getRFonts();//获取里的 if (font == null) {//没有,创建 font = rpr.addNewRFonts(); } //设置字体 font.setAscii(fontName); font.setEastAsia(fontName); font.setHAnsi(fontName); CTOnOff b = rpr.getB();//获取里的 if (b == null) {//没有,创建 b = rpr.addNewB(); } //设置字体是否加粗 b.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF); CTColor color = rpr.getColor();//获取里的 if (color == null) {//没有,创建 color = rpr.addNewColor(); } // 设置字体颜色 if (content.contains("↓")) { color.setVal("43CD80"); } else if (content.contains("↑")) { color.setVal("943634"); } else { color.setVal(fontColor.substring(1)); } CTHpsMeasure sz = rpr.getSz(); if (sz == null) { sz = rpr.addNewSz(); } sz.setVal(bFontSize); CTHpsMeasure szCs = rpr.getSzCs(); if (szCs == null) { szCs = rpr.addNewSz(); } szCs.setVal(bFontSize); //- 0) { for (XWPFParagraph paragraph : paragraphList) { List runs = paragraph.getRuns(); for (XWPFRun run : runs) { String text = run.getText(0); if (text != null) { // 动态表格 if (text.contains("${table1}")) { run.setText("", 0); XmlCursor cursor = paragraph.getCTP().newCursor(); XWPFTable tableOne = doc.insertNewTbl(cursor);// ---这个是关键 // 设置表格宽度,第一行宽度就可以了,这个值的单位,目前我也还不清楚,还没来得及研究 tableOne.setWidth(8500); // 表格第一行,对于每个列,必须使用createCell(),而不是getCell(),因为第一行嘛,肯定是属于创建的,没有create哪里来的get呢 XWPFTableRow tableOneRowOne = tableOne.getRow(0);//行 new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "序号"); new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(英文)"); new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(中文)"); for (int i = 0; i < 10; i ++) { // 表格第二行 XWPFTableRow tableOneRowTwo = tableOne.createRow();//行 new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "10%", "一行一列"); new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(1), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "45%", "一行一列"); new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(2), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "45%", "一行一列"); } // 横着合并单元格 ----------------------------- XWPFTableCell cell71 = tableOne.getRow(6).getCell(0); // 第7行的第1列 XWPFTableCell cell72 = tableOne.getRow(6).getCell(1); // 第7行的第2列 XWPFTableCell cell73 = tableOne.getRow(6).getCell(2); // 第7行的第3列 cell71.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); cell72.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); cell73.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); // 竖着合并单元格 ----------------------------- XWPFTableCell cell1 = tableOne.getRow(1).getCell(0); // 第2行第1列 第1行是表头 XWPFTableCell cell2 = tableOne.getRow(2).getCell(0); // 第3行第1列 XWPFTableCell cell3 = tableOne.getRow(3).getCell(0); // 第4行第1列 XWPFTableCell cell4 = tableOne.getRow(4).getCell(0); // 第5行第1列 cell1.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART); cell2.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); cell3.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); cell4.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); // ....... } } } } } } }

4:结果:

两种方式本质上是一样的!

2020-04-23:解决问题:组合图页面显示的数据,跟第二列对应不上(感谢博友:吹古拉朽)

事情是这样的,博客网友吹古拉朽说,组合图页面显示的数据,跟第二列对应不上,柱状图+折线图的图表,折线图会显示柱状图的数据,显示结果如下图:很明显是不对的;

 如果你已经运行过我的示例代码中的PoiDemoWordTable.java这个类,生成的第6个图表,就是这个;

解决方案:在第六个图表对应的代码中,修改position参数的值,如图:这个参数代表数据下标,从0开始的。

所以我这里改成3就好了。

本文示例源代码:(码云地址)poi-demo: poi使用demo,主要用于word生成各种图表元素



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有