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";
}
}
暂无评论内容