Excel导出带有多个图表(柱状图、折线图、饼状图等)

说明

动态创建带有多个图表的Excel文件

效果图:
在这里插入图片描述

一、分析

第一种:创建图表模板,在Excel模板里设置好图表,然后通过更新模板数值,最终刷新图表;(也包含刷新图标各项数据)
第二种:动态创建带有数值与图表的Excel

说明:第一种,有一定的局限性,就是Excel里的数值与图表的格式需要固定,只是对数值进行替换。实际开发过程中,很少有固定的格式,所以重点讲解第二种;

二、全动态导出Excel带有多个图表–》实现步骤

第一步:根据传入的数据集,生成数据表的表头与数据行,并返回创建画布XSSFDrawing
第二步:在画布里创建空图表XSSFChart
第三步:设置图表XSSFChart,比如:创建柱状图
第四步:生成导出Excel文件

1.根据传入的数据集,生成数据表的表头与数据行

创建数据源,就是创建列头,数据行以及样式等;
一个sheet对应一个画布,所有返回一个画布;
代码如下:

private XSSFDrawing createXSSFDrawingBuildDataSource(ExcelMoreDataSourceInput input) {
        if (Objects.isNull(wb)) wb = new XSSFWorkbook();

        XSSFSheet sheet = wb.createSheet(input.getSheetName());
        // 创建数据源
        drawTable(sheet, input.getTitleArr(), input.getFldNameArr(), input.getDataList());
        // 创建一个画布
        return sheet.createDrawingPatriarch();
    }

2.在画布里创建空图表XSSFChart

在画布里创建空图表XSSFChart,设置第几行几列为图表(多个图表布局好即可)
代码如下:

    /**
     * 创建图表
     *
     * @param isPutOnRight 比如:当列数大于5时,把画布放在数组右边
     * @param chartNum     创建第几个图表
     */
    private XSSFChart createChart(XSSFDrawing drawing, int cols, int rows, boolean isPutOnRight, int chartNum) {
        int colNum = 25;
        ClientAnchor anchor;
        if (isPutOnRight) {
            anchor = drawing.createAnchor(0, 0, 0, 0, 1, rows + 2 + colNum * (chartNum - 1), cols + 15, rows + colNum * chartNums);
        } else {
            anchor = drawing.createAnchor(0, 0, 0, 0, cols + 1, 4 + colNum * (chartNum - 1), cols + 15, colNum * chartNums);
        }

        // 创建一个chart对象
        return drawing.createChart(anchor);
    }

3.设置图表XSSFChart

以制作柱状图为例:
1、确认哪些列作为图例项
2、设置横坐标,这里固定第一列为横坐标
3、设置数据区域范围
具体请看一下代码
代码如下:

    /**
     * 生成柱状图
     *
     * @param chart           图表
     * @param group           柱状图类型(堆积,多组)
     * @param fldNameArrIndex 数据列下标(用于Excel标识数据源区域)
     * @param rows            数据行数
     * @param sheetName       sheet的名称
     */
    private void drawBarChartMap(XSSFChart chart, STBarGrouping.Enum group, int[] fldNameArrIndex, int rows, String sheetName) {
        CTChart ctChart = chart.getCTChart();
        CTPlotArea ctPlotArea = ctChart.getPlotArea();
        // 创建柱状图模型
        CTBarChart ctBarChart = ctPlotArea.addNewBarChart();
        CTBoolean ctBoolean = ctBarChart.addNewVaryColors();
        ctBarChart.getVaryColors().setVal(true);
        // 设置图类型
        ctBarChart.addNewGrouping().setVal(group);
        ctBoolean.setVal(true);
        ctBarChart.addNewBarDir().setVal(STBarDir.COL);
        // 是否添加左侧坐标轴
        ctChart.addNewDispBlanksAs().setVal(STDispBlanksAs.ZERO);
        ctChart.addNewShowDLblsOverMax().setVal(true);
        // 设置这两个参数是为了在STACKED模式下生成堆积模式;(standard)标准模式时需要将这两行去掉
        if ("stacked".equals(group.toString()) || "percentStacked".equals(group.toString())) {
            ctBarChart.addNewGapWidth().setVal(150);
            ctBarChart.addNewOverlap().setVal((byte) 100);
        }
        // 创建序列,并且设置选中区域
        for (int i = 0; i < fldNameArrIndex.length; i++) {
            int col = fldNameArrIndex[i];
            CTBarSer ctBarSer = ctBarChart.addNewSer();
            CTSerTx ctSerTx = ctBarSer.addNewTx();
            // 图例区
            CTStrRef ctStrRef = ctSerTx.addNewStrRef();
            // 选定区域第0行,第1,2,3列标题作为图例 //1 2 3
            String legendDataRange = new CellRangeAddress(0, 0, col, col).formatAsString(sheetName, true);
            ctStrRef.setF(legendDataRange);
            ctBarSer.addNewIdx().setVal(i);
            // 横坐标区
            CTAxDataSource cttAxDataSource = ctBarSer.addNewCat();
            ctStrRef = cttAxDataSource.addNewStrRef();
            // 选第0列为横坐标区域
            String axisDataRange = new CellRangeAddress(1, rows, 0, 0).formatAsString(sheetName, true);
            ctStrRef.setF(axisDataRange);
            // 数据区域
            CTNumDataSource ctNumDataSource = ctBarSer.addNewVal();
            CTNumRef ctNumRef = ctNumDataSource.addNewNumRef();
            // 选第1-6行,第1-3列作为数据区域 //1 2 3
            String numDataRange = new CellRangeAddress(1, rows, col, col).formatAsString(sheetName,
                true);
            ctNumRef.setF(numDataRange);
            // 添加柱状边框线
            ctBarSer.addNewSpPr().addNewLn().addNewSolidFill().addNewSrgbClr().setVal(new byte[]{0, 0, 0});
            // 设置负轴颜色不是白色
            ctBarSer.addNewInvertIfNegative().setVal(false);
            // 设置标签格式
            ctBoolean.setVal(false);
            CTDLbls newDLbls = ctBarSer.addNewDLbls();
            newDLbls.setShowLegendKey(ctBoolean);
            ctBoolean.setVal(true);
            newDLbls.setShowVal(ctBoolean);
            ctBoolean.setVal(false);
            newDLbls.setShowCatName(ctBoolean);
            newDLbls.setShowSerName(ctBoolean);
            newDLbls.setShowPercent(ctBoolean);
            newDLbls.setShowBubbleSize(ctBoolean);
            newDLbls.setShowLeaderLines(ctBoolean);
        }
        // 告诉BarChart它有坐标轴,并给它们id
        ctBarChart.addNewAxId().setVal(123456);
        ctBarChart.addNewAxId().setVal(123457);
        // 横坐标
        CTCatAx ctCatAx = ctPlotArea.addNewCatAx();
        ctCatAx.addNewAxId().setVal(123456); // id of the cat axis
        CTScaling ctScaling = ctCatAx.addNewScaling();
        ctScaling.addNewOrientation().setVal(STOrientation.MIN_MAX);
        ctCatAx.addNewAxPos().setVal(STAxPos.B);
        ctCatAx.addNewCrossAx().setVal(123457); // id of the val axis
        ctCatAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);
        // 纵坐标
        CTValAx ctValAx = ctPlotArea.addNewValAx();
        ctValAx.addNewAxId().setVal(123457); // id of the val axis
        ctScaling = ctValAx.addNewScaling();
        ctScaling.addNewOrientation().setVal(STOrientation.MIN_MAX);
        // 设置位置
        ctValAx.addNewAxPos().setVal(STAxPos.L);
        ctValAx.addNewCrossAx().setVal(123456); // id of the cat axis
        ctValAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);
        // 是否删除主左边轴
        ctValAx.addNewDelete().setVal(false);
        // 是否删除横坐标
        ctCatAx.addNewDelete().setVal(false);
        // legend图注
        // if(true){
        CTLegend ctLegend = ctChart.addNewLegend();
        ctLegend.addNewLegendPos().setVal(STLegendPos.B);
        ctLegend.addNewOverlay().setVal(false);
        // }
    }

4.生成导出Excel文件

代码如下:

    public void createTpl(String filePath) {
        try {
            File f = new File(filePath); //写文件
            //不存在则新增
            if (!f.getParentFile().exists()) {
                f.getParentFile().mkdirs();
            }
            if (!f.exists()) {
                f.createNewFile();
            }

            FileOutputStream out = new FileOutputStream(f);
            out.flush();
            wb.write(out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

三、测试用例

/**
 * 根据数据源,生成多个图表
 */
public class ExcelChartUtilTest {

    @Test
    public void excelChartTest() {
        // 字段名
        List<String> fldNameArr = new ArrayList<>();
        fldNameArr.add("value1");
        fldNameArr.add("value2");
        fldNameArr.add("value3");
        fldNameArr.add("value4");
        // 列头
        List<String> titleArr = new ArrayList<>();
        titleArr.add("类型");
        titleArr.add("总额");
        titleArr.add("数量");
        titleArr.add("人均");
        // 模拟数据
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Map<String, Object> dataMap_ = new HashMap<>();
            dataMap_.put("value1", "类型" + i);
            dataMap_.put("value2", Math.floor(Math.random() * 100) + "");
            dataMap_.put("value3", i);
            dataMap_.put("value4", Math.floor(Math.random() * 10));
            dataList.add(dataMap_);
        }

        //开始赋值
        ExcelMoreDataSourceInput input = new ExcelMoreDataSourceInput();
        input.setTitleArr(titleArr);
        input.setFldNameArr(fldNameArr);
        input.setDataList(dataList);

        // 固定第一列为横坐标区域
        List<ChartDataSource> chartDataSources = Lists.newArrayList();
        ChartDataSource dataSource = new ChartDataSource();
        dataSource.setChartType(ChartType.LINE);
        dataSource.setLegendItems(Lists.newArrayList("value2"));

        ChartDataSource dataSource1 = new ChartDataSource();
        dataSource1.setChartType(ChartType.BAR);
        dataSource1.setLegendItems(Lists.newArrayList("value2", "value3", "value4"));

        chartDataSources.add(dataSource);
        chartDataSources.add(dataSource1);
        input.setChartDataSources(chartDataSources);

        ExcelChartMoreUtil moreUtil = new ExcelChartMoreUtil(input);
        String pathName = "C:/file/chart/chartMore.xlsx";
        moreUtil.createTpl(pathName);
    }
}

根据模板生成图标(更新数值,从而刷新图标)

模板内容:
在这里插入图片描述
执行测试方法后,效果图下:
在这里插入图片描述

代码如下:

@Test
    public void chart_fixed_row_column_test() throws Exception {

        final String fileInput = "C:\\file\\chart\\test\\line-chart-template-test.xlsx";
        try (FileInputStream argIS = new FileInputStream(fileInput)) {
            try (XSSFWorkbook xssfWorkbook = new XSSFWorkbook(argIS)) {
                //获取创建工作簿的第一页
                XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
                //自动计算
                sheet.setForceFormulaRecalculation(true);
                //给指定的sheet命名
                xssfWorkbook.setSheetName(0, "sheet0");
                //初始化当前的索引,设为当前sheet的最后一行行数
                int allRows = sheet.getLastRowNum();

                //填充数据
                for (int i = 1; i <= allRows; i++) {
                    XSSFRow row = sheet.getRow(i);
                    if (row == null) {
                        continue;
                    }

                    //遍历列
                    for (int j = 0; j < 4; j++) {
                        XSSFCell cell = row.getCell(j) != null ? row.getCell(j) : row.createCell(j);
                        String cellValue = cell.getStringCellValue();
                        if (cellValue.startsWith("#")) {
                            if (j == 0) cell.setCellValue("岗位" + i);
                            else cell.setCellValue(i * 10 + j);
                        }
                    }
                    // 保存返回
                    try (OutputStream out = new FileOutputStream("C:\\file\\chart\\test\\line_chart-demo-output.xlsx")) {
                        xssfWorkbook.write(out);
                    }
                }
            }
        }
    }
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值