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,3,6,18),表示从y轴第1个单元格开始,画到第6个。需要注意后面的值一定要比前面的值大。
使用说明6:如写成(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;/*** @description:表格添加柱形图表* @author: xiongsg* @create: 2024/11/21 14:48* @Version 1.0**/
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年");//ChartEntity chartEntity = new ChartEntity("LINE", 0, 3, 18, 3, "柱形图", "X轴", "Y轴");//表格添加柱形图表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 chartXSSFDrawing 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("线性")) {// NOSONAR// 虚线lineProperties.setPresetDash(new XDDFPresetLineDash(PresetLineDash.DOT));}shapeProperties.setLineProperties(lineProperties);series.setLineProperties(lineProperties);}//lineProperties.setWidth(1.5);lineProperties.setLineCap(LineCap.FLAT);}//设置数字标签 但是会显示所有的数据如x周的数据 所以要取消掉其他的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);}
}