# poi 生成word统计图表

基于word 模板生成柱状图、条形图、饼图等

# 效果图

模板的原始效果:

image-20241213172237613

生成之后的效果:

image-20241213170735818

# 生成统计图

word 生成统计图表有多种方式,比如通过渲染直接生成,还可以借助图表工具生成图片,然后引入到 word 中。本文介绍的是基于模板生成统计图表。

我们打开一个正常的统计图表,然后右击选择 “编辑数据”,发现其实它的数据源对应的就是一个 excel ,我们把对应的 excel 数据编辑也就完成了图表的生成。

image-20241213172100095

image-20241213172112888

# 具体实现代码

poi 版本为:4.1.2

package org.demo;

import cn.hutool.core.util.RandomUtil;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.List;

//需要注意的是excel 第一行对应的索引为0!!!
class ExcelChangeChartData {

    public static void main(String[] args) throws Exception {

        //数据范围的开始行
        int firstDataRow = 1;
        //数据范围的结束行
        int lastDataRow = 0;
        //类目所对应的列
        int categoryColumn = 0;
        //数据对应的列,示例中展示的是一个双维度的柱状图,索引这里是2个元素,分别对应了数据列的位置
        int[] seriesColumns = new int[]{1, 2};
		//读取模板
        FileInputStream fis = new FileInputStream("D:\\test-file\\example.docx");
        XWPFDocument doc = new XWPFDocument(fis);
        //获取图表对象
        List<XWPFChart> charts = doc.getCharts();
        //拿到第一个图表
        XWPFChart chart = charts.get(0);

        //对应的类目
        String[] months = new String[]{"11.1", "11.2", "11.3"};
        for (int m = 0; m < months.length; m++) {
            String monthResult = months[m ];
            XSSFWorkbook workbook = chart.getWorkbook();
            //可以理解为 获取excel实例
            XSSFSheet sheet = workbook.getSheetAt(0);
            //创建一行数据,其实这里是第2行数据,第2行数据模板里边已经有了就是对应的  日志系统告警	订单系统告警
            XSSFRow row = sheet.createRow(lastDataRow + 1);
            //根据下标创建单元格 这里创建的是类目所对应的单元格
            XSSFCell cell = row.createCell(categoryColumn);
            //设置类目的值
            cell.setCellValue(monthResult);
            //遍历添加测试数据
            for (int i = 0; i < seriesColumns.length; i++) {
                cell = row.createCell(seriesColumns[i]);
                cell.setCellValue(RandomUtil.randomInt(10, 100));
            }

            lastDataRow++;
            //获取图表对应数据集
            XDDFChartData chartData0 = chart.getChartSeries().get(0);
            updateChartData(Arrays.asList(chartData0), sheet, firstDataRow, lastDataRow, categoryColumn, seriesColumns);
        }
        FileOutputStream fos = new FileOutputStream("D:\\test-file\\example-1.docx");
        doc.write(fos);
        //这里的关闭不是很合适,请注意处理关闭的异常情况
        fos.close();
        doc.close();
        fis.close();
    }
    
    //刷新图表数据到word
        static void updateChartData(List<XDDFChartData> chart, XSSFSheet dataSheet,
                                int firstDataRow, int lastDataRow, int categoryColumn, int[] seriesColumns) {

        for (XDDFChartData chartData : chart) {s
            for (int s = 0; s < chartData.getSeriesCount(); s++) {
                XDDFChartData.Series series = chartData.getSeries(s);
                if (seriesColumns.length > s) {
                    //生成类目数据 firstDataRow 开始行 lastDataRow 结束行 categoryColumn 对应列索引 
                    XDDFCategoryDataSource category = XDDFDataSourcesFactory.fromStringCellRange(
                            dataSheet, new CellRangeAddress(firstDataRow, lastDataRow, categoryColumn, categoryColumn));
                    //获取维度引用列 
                    int seriesColumn = seriesColumns[s];
                    XDDFNumericalDataSource<Double> values = XDDFDataSourcesFactory.fromNumericCellRange(
                            dataSheet, new CellRangeAddress(firstDataRow, lastDataRow, seriesColumn, seriesColumn));
                    series.replaceData(category, values);
                    series.plot();
                }
            }
        }
    }
}
上次更新: 2024/12/16