Java+POI+EXCEL导出柱形图(多列和单列柱形图)

1、问题概述?

本案例使用POI版本:5.2.3

再项目中我们经常需要将项目中的数据以图标的形式导出,以下是,以JAVA+POI技术,将对象的数据写入到excel表格中,样式如下:

主要分为两种:多列柱形图和,单列柱形图

2、实现方式–多列柱形图

2.1、导入依赖包-案例完整pom.xml文件

此处需要注意,我是用的spring boot版本是2.17.6版本。

同时需要注意commons-lang3的版本,版本尽量高一些,否则会报错,我使用的是3.12.0。我是用2.4版本报错,测试过2.16.1版本不报错。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.16</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>testdemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>testdemo</name>
	<description>testdemo</description>
	<properties>
		<java.version>17</java.version>
		<itext7.version>7.1.7</itext7.version>
		<itext7.html2pdf.version>2.1.4</itext7.html2pdf.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>5.2.4</version>
		</dependency>

		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>5.2.3</version>
		</dependency>

		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-full</artifactId>
			<version>5.2.2</version>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2.2、报表位置解释

使用说明1:前四个参数固定使用0就可以了。

使用说明2:第五和第七个参数,表示从第几行画到第几行结束。

使用说明3:第六和第八参数,表示从第几列画到第几列结束。

使用说明5:如写成(0,0,0,0,0,3,6,18),表示从y轴第1个单元格开始,画到第6个。需要注意后面的值一定要比前面的值大。

使用说明6:如写成,0,0,0,0,0,3,6,18),表示从x轴第3个单元格开始,画到第18个。需要注意后面的值一定要比前面的值大。

//表示从y周第一个单元开始,画到y轴第6个单元格,宽3个单元格。x轴地三个单元格开始,画到x轴地18行,高15个单元格。

XSSFDrawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 3, 6, 18);
XSSFChart chart = drawing.createChart(anchor);

2.3、完整测试代码–多列柱形图

单列和多列柱形图,最大的区别在于,需要的数据类型是不同的。

package com.example.testdemo.controller;
import com.example.testdemo.bean.ChartEntity;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBoolean;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 向excel写入柱形图
 **/
public class BarChartExample {
    public static void main(String[] args) throws IOException {
        //创建一个模板表格,直接创建一个就可以了。
        File file=new File("C:\Users\Administrator\Desktop\test.xlsx");
        InputStream in=new FileInputStream(file);
        XSSFWorkbook  workbook=new XSSFWorkbook(in);

        //获取报表的第一个报表
        XSSFSheet sheet = workbook.getSheetAt(0);
        List<List<Object>> sheetDataList = new ArrayList<>();
        List<Object> list1 = Arrays.asList("完成", 20.0, 40.0, 70.0);
        List<Object> list2 = Arrays.asList("失败", 10.0, 5.0, 0.0);
        List<Object> list3 = Arrays.asList("未执行",50.0, 30.0,10.0);
        sheetDataList.add(list1);
        sheetDataList.add(list2);
        sheetDataList.add(list3);
        List<Object> heads = Arrays.asList("","2022年", "2023年", "2024年", "2025年");
        //创建柱形图
        createBarChart(sheet, sheetDataList, heads);
        // 保存工作簿,将工作簿保存再桌面
        try (FileOutputStream fileOut = new FileOutputStream("C:\Users\Administrator\Desktop\testExample.xlsx")) {
            workbook.write(fileOut);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //关闭资源
        try {
            workbook.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 向excel写入柱形图
     */
    public static void createBarChart(XSSFSheet sheet, List<List<Object>> sheetDataList, List<Object> heads) {
        //y轴显示数据
        String[] headArray = heads.stream().skip(1).collect(Collectors.toList()).toArray(new String[]{});

        // Create a chart
        XSSFDrawing drawing = sheet.createDrawingPatriarch();
        ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 3, 6, 18);
        XSSFChart chart = drawing.createChart(anchor);
        //标题是否覆盖图表
        chart.setTitleOverlay(false);
        //设置图表标题
        chart.setTitleText("这是报表的名字");

        // 创建图表系列
        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.TOP);
        XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
        XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.LEFT);
        //设置柱表两端的柱子 不要被遮挡
        yAxis.setCrossBetween(AxisCrossBetween.BETWEEN);

        //x轴数据
        XDDFDataSource<String> xData = XDDFDataSourcesFactory.fromArray(headArray);
        //设置柱形图数据
        XDDFBarChartData data = (XDDFBarChartData) chart.createData(ChartTypes.BAR, xAxis, yAxis);
        data.setBarDirection(BarDirection.COL);
        data.setVaryColors(true);
        for (List<Object> objects : sheetDataList) {
            String title = String.valueOf(objects.get(0));
            Double[] yArray = objects.stream().skip(1).collect(Collectors.toList()).toArray(new Double[]{});
            //y轴数据
            XDDFNumericalDataSource<Double> yData = XDDFDataSourcesFactory.fromArray(yArray);
            XDDFChartData.Series series = data.addSeries(xData, yData);
            series.setTitle(title, null);
            series.setShowLeaderLines(true);
            XDDFShapeProperties shapeProperties = series.getShapeProperties();
            if (shapeProperties == null) {
                shapeProperties = new XDDFShapeProperties();
                series.setShapeProperties(shapeProperties);
            }
            XDDFLineProperties lineProperties = shapeProperties.getLineProperties();
            if (lineProperties == null) {
                lineProperties = new XDDFLineProperties();
                if (title.contains("线性")) {
                    lineProperties.setPresetDash(new XDDFPresetLineDash(PresetLineDash.DOT));
                }
                shapeProperties.setLineProperties(lineProperties);
                series.setLineProperties(lineProperties);
            }
            //lineProperties.setWidth(1.5);
            lineProperties.setLineCap(LineCap.FLAT);
        }
        CTPlotArea plotArea = chart.getCTChart().getPlotArea();
        for (CTBarSer ser : plotArea.getBarChartArray(0).getSerList()) {
            CTBoolean ctBoolean = CTBoolean.Factory.newInstance();
            ctBoolean.setVal(false);
            CTDLbls ctdLbls = ser.addNewDLbls();
            ctdLbls.addNewShowVal().setVal(true);
            ctdLbls.addNewNumFmt().setFormatCode("#");
            ctdLbls.setShowBubbleSize(ctBoolean);
            ctdLbls.setShowCatName(ctBoolean);
            ctdLbls.setShowLeaderLines(ctBoolean);
            ctdLbls.setShowLegendKey(ctBoolean);
            ctdLbls.setShowSerName(ctBoolean);
            ctdLbls.setShowPercent(ctBoolean);
        }
        chart.plot(data);
    }
}

3、实现方式-单列柱形图

案例的重点就是数据的类型和样子。

在这个案例中,我将柱形图需要的数据,已aa和bb明确的列出,你只需要将你的数据转化成对应的格式即可。

package com.example.testdemo.utils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.PresetColor;
import org.apache.poi.xddf.usermodel.XDDFColor;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 单列柱形图
 */
public class ExcelChartUtils {

    //这个test1.xlsx没有特殊之处,之间在桌面创建一个就可以了。
    public static final String READ_FILE_PATH = "C:\Users\Administrator\Desktop\test1.xlsx";

    public static void main(String[] args) throws IOException {
        ExcelChartUtils  excelChartUtils=new ExcelChartUtils();
        FileInputStream fis = new FileInputStream(READ_FILE_PATH);
        XSSFWorkbook wb = new XSSFWorkbook(fis);

        excelChartUtils.exportBarDiagram(wb);

    }

    public String exportBarDiagram(XSSFWorkbook wb) throws IOException {

        FileOutputStream fileOut = null;
        try {
            XSSFSheet sheet = wb.getSheetAt(0);
            // 创建画布
            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 3, 3, 15, 20);
            XSSFChart chart = drawing.createChart(anchor);
            //设置标题标题
            chart.setTitleText("幼儿园平均身高");
            chart.setTitleOverlay(false);

            // 图例位置
            XDDFChartLegend legend = chart.getOrAddLegend();
            legend.setPosition(LegendPosition.TOP);

            // 分类轴标(X轴),标题位置
            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
            // x轴数据
            String []aa=new String[]{"小一班","小二班","小三班","小四班","小五班"};
            XDDFCategoryDataSource countries = XDDFDataSourcesFactory.fromArray(aa);
            // XDDFNumericalDataSource<Double> area = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, 6));
            //y轴数据
            Integer []bb=new Integer[]{100,109,106,120,98};
            XDDFNumericalDataSource<Integer> area = XDDFDataSourcesFactory.fromArray(bb);
            //
            XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);

            leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
            // 设置为可变颜色,false表示可变,true表示不可变。
            bar.setVaryColors(false);
            // 条形图方向,纵向/横向:纵向
            bar.setBarDirection(BarDirection.COL);
            // 图表加载数据,条形图1
            XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(countries, area);
            // 条形图例标题
            series1.setTitle("幼儿班平均身高", null);
            XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.GREEN_YELLOW));
            // 条形图,填充颜色
            series1.setFillProperties(fill);
            // 绘制
            chart.plot(bar);
            fileOut = new FileOutputStream(READ_FILE_PATH);
            wb.write(fileOut);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            wb.close();
            if (fileOut != null) {
                fileOut.close();
            }
        }

        return "success";
    }

 
}


© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容