springboot实现对接poi 导出excel折线图

在Spring Boot项目中,使用Apache POI库可以实现将数据导出为Excel并嵌入动态生成的折线图。下面为您详细介绍具体的实现步骤、核心代码以及注意事项。

🔧 环境准备:添加依赖

首先,在您的pom.xml文件中添加必要的依赖。推荐使用较新版本的POI以确保功能稳定。

xml 复制代码
<dependencies>
    <!-- Spring Boot Web 支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Apache POI 核心库 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.3</version>
    </dependency>
    <!-- 处理 xlsx 格式的OOXML支持 -->
    <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-schemas</artifactId>
        <version>4.1.2</version>
    </dependency>
</dependencies>

📊 定义数据模型

为了清晰管理图表数据和在Excel中的位置,建议先定义两个实体类。 ​​1. 折线图数据模型 (LineChart):​​ 这个类用于封装折线图的所有元素,包括标题、数据系列和X轴标签。

swift 复制代码
@Data
@Accessors(chain = true)
public class LineChart {
    /**
     * 图表的名称(主标题)
     */
    private String chartTitle;
    /**
     * 每条折线的名称(图例)
     */
    private List<String> titleList;
    /**
     * 每条折线对应的数据值
     */
    private List<List<Double>> dataList;
    /**
     * X轴的数据点标签(如:月份、季度)
     */
    private List<Object> xAxisList;
}

​2. 图表位置模型 (ChartPosition):​​ 这个类用于精确定义图表在Excel工作表中的位置和大小。

arduino 复制代码
@Data
@Accessors(chain = true)
public class ChartPosition {
    /** 图表左上角所在的列索引(从0开始) */
    private int col1;
    /** 图表左上角所在的行索引(从0开始) */
    private int row1;
    /** 图表右下角所在的列索引 */
    private int col2;
    /** 图表右下角所在的行索引 */
    private int row2;
    // 以下偏移量通常可设为0
    private int dx1 = 0;
    private int dy1 = 0;
    private int dx2 = 0;
    private int dy2 = 0;
}

🛠️ 核心工具类:创建折线图

这是最关键的步骤,我们将创建一个工具类ChartUtils,其中的createLine方法负责在指定的Excel工作表中绘制折线图。

ini 复制代码
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.charts.*;
import org.apache.poi.xddf.usermodel.chart.*;

public class ChartUtils {
    
    public static void createLine(XSSFSheet sheet, ChartPosition chartPosition, LineChart lineChart) {
        // 1. 获取数据
        List<Object> xAxisList = lineChart.getXAxisList();
        List<String> chartTitleList = lineChart.getTitleList();
        List<List<Double>> chartDataList = lineChart.getDataList();
        String chartTitle = lineChart.getChartTitle();

        // 2. 创建绘图对象和图表锚点
        XSSFDrawing drawing = sheet.createDrawingPatriarch();
        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 
                                                     chartPosition.getCol1(), chartPosition.getRow1(), 
                                                     chartPosition.getCol2(), chartPosition.getRow2());
        // 3. 创建图表并设置标题
        XSSFChart chart = drawing.createChart(anchor);
        chart.setTitleText(chartTitle);
        chart.setTitleOverlay(false);

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

        // 5. 创建坐标轴
        XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);

        // 6. 准备数据源
        // 6.1 X轴数据(类别)
        XDDFCategoryDataSource countries = XDDFDataSourcesFactory.fromArray(
                Arrays.copyOf(xAxisList.toArray(), xAxisList.size(), String[].class));
        // 6.2 创建折线图数据对象
        XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);

        // 7. 为每个数据系列创建折线
        for (int i = 0; i < chartDataList.size(); i++) {
            List<Double> values = chartDataList.get(i);
            // 创建Y轴数据源
            XDDFNumericalDataSource<Double> dataSource = XDDFDataSourcesFactory.fromArray(
                    values.toArray(new Double[0]));
            
            // 将数据系列添加到图表
            XDDFLineChartData.Series series = (XDDFLineChartData.Series) data.addSeries(countries, dataSource);
            series.setTitle(chartTitleList.get(i), null);
            series.setSmooth(false); // 设置为折线,非平滑曲线
            series.setMarkerSize((short) 2); // 设置数据点标记的大小

            // (可选)特殊样式处理,例如为"警戒值"设置虚线
            if ("警戒值".equals(chartTitleList.get(i))) {
                XDDFLineProperties lineProps = new XDDFLineProperties();
                lineProps.setPresetDash(new XDDFPresetLineDash(PresetLineDash.DOT));
                series.setLineProperties(lineProps);
            }
        }

        // 8. 绘制图表
        chart.plot(data);
    }
}

🚀 业务层整合与导出接口

最后,在Spring Boot的Controller中,将数据导出和图表生成功能整合起来,提供一个HTTP接口供前端调用。

java 复制代码
@RestController
public class ExcelExportController {

    @GetMapping("/export/excel-with-chart")
    public void exportExcelWithChart(HttpServletResponse response) throws IOException {
        // 1. 设置响应头,告诉浏览器这是一个要下载的Excel文件
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename="data_with_chart.xlsx"");
        
        // 2. 创建工作簿和工作表
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("数据报表");
        
        // 3. (可选)向工作表填充数据行...
        // 例如:createDataRows(sheet);
        
        // 4. 准备折线图数据
        LineChart lineChart = new LineChart()
                .setChartTitle("销售趋势图")
                .setXAxisList(Arrays.asList("1月", "2月", "3月", "4月", "5月"))
                .setTitleList(Arrays.asList("产品A", "产品B", "警戒值"))
                .setDataList(Arrays.asList(
                        Arrays.asList(120.0, 150.0, 180.0, 160.0, 200.0),
                        Arrays.asList(90.0, 120.0, 140.0, 130.0, 150.0),
                        Arrays.asList(150.0, 150.0, 150.0, 150.0, 150.0) // 警戒线
                ));
        
        // 5. 定义图表位置(例如:从第0行第0列开始,到第15行第10列结束)
        ChartPosition position = new ChartPosition()
                .setCol1(0).setRow1(10).setCol2(10).setRow2(25);
        
        // 6. 调用工具类创建折线图
        ChartUtils.createLine(sheet, position, lineChart);
        
        // 7. 将工作簿写入HTTP响应流
        OutputStream out = response.getOutputStream();
        workbook.write(out);
        workbook.close();
        out.flush();
    }
}

💡 关键要点与优化建议

在实际使用中,请注意以下几点以确保最佳效果:

  • ​版本兼容性​ :确保所有POI相关依赖(如poi, poi-ooxml, poi-ooxml-schemas)的版本一致,以避免潜在的冲突。
  • ​图表位置规划​ :在插入图表前,最好先规划好数据表格的布局。ChartPosition中的行索引应考虑表格已占用的行数,防止图表覆盖数据。
  • ​大数据量优化​ :当需要导出的数据量非常大时,建议使用SXSSFWorkbook来代替XSSFWorkbook,它以流式处理方式工作,可以显著降低内存消耗。
  • ​前端调用​ :前端Vue或React应用可以使用axios等库调用此导出接口,并通过处理返回的Blob对象实现文件下载。

通过以上步骤,您就可以在Spring Boot应用中灵活地导出包含专业折线图的Excel报表了。这套方法可以根据实际业务需求,轻松调整以生成柱状图或饼图等其他图表类型。

相关推荐
金銀銅鐵3 小时前
[Java] 如何自动生成简单的 Mermaid 类图
java·后端
Hard but lovely3 小时前
C++---》stl : pair 从使用到模拟实现
c++·后端
纵横八荒3 小时前
Java基础加强13-集合框架、Stream流
java·开发语言
稚辉君.MCA_P8_Java4 小时前
kafka解决了什么问题?mmap 和sendfile
java·spring boot·分布式·kafka·kubernetes
乄bluefox4 小时前
保姆级docker部署nacos集群
java·docker·容器
欣然~4 小时前
百度地图收藏地址提取与格式转换工具 说明文档
java·开发语言·dubbo
app出海创收老李4 小时前
海外独立创收日记(5)-上个月收入回顾与本月计划
前端·后端·程序员
每天进步一点_JL4 小时前
Docker 是什么?
后端·docker·容器
玩毛线的包子4 小时前
Android Gradle学习(十三)- 配置读取和文件写入
java