Java实现大数据量导出报表

news2025/3/5 9:33:45

一、实现方式

在Java中,导出数据到Excel有多种方式,每种方式都有其优缺点,适用于不同的场景。以下是常见的几种方式及其特点:

1.1 Apache POI

Apache POI 是 Java 中最流行的库,支持读写 Excel 文件(包括 .xls 和 .xlsx 格式)。

  • 特点:
    • 支持 .xls(HSSFWorkbook)和 .xlsx(XSSFWorkbook、SXSSFWorkbook)。
    • 功能强大,支持样式、公式、图表等。
    • SXSSFWorkbook 支持流式写入,适合大数据量导出。
  • 适用场景:
    • 需要导出复杂格式的 Excel 文件。
    • 大数据量导出(使用 SXSSFWorkbook)。
1.2 EasyExcel

EasyExcel 是阿里巴巴开源的 Excel 操作库,基于 Apache POI 封装,专注于大数据量导出和导入。

  • 特点:
    • 支持流式读写,内存占用低。
    • API 简单易用。
    • 支持 .xlsx 格式。
  • 适用场景:
    • 大数据量导出(百万级数据)。
    • 需要高性能和低内存占用的场景。
1.3 OpenCSV

虽然不是直接导出 Excel 文件,但 CSV 文件可以被 Excel 直接打开,适合简单的数据导出。

  • 特点:
    • 轻量级,速度快。
    • 文件格式简单,不支持样式、公式等。
    • 适合纯数据导出。
  • 适用场景:
    • 数据量较大,且不需要复杂格式。
    • 需要快速导出和导入。

二、使用SXSSFWorkbook

2.1 添加依赖

在pom.xml中添加Apache POI依赖:

<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>
2.2 定义数据模型

创建一个 Java 类表示导出的数据模型。

public class DataModel {
    private Long id;
    private String name;
    private Double value;

    // 构造方法、Getter 和 Setter
    public DataModel(Long id, String name, Double value) {
        this.id = id;
        this.name = name;
        this.value = value;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getValue() {
        return value;
    }

    public void setValue(Double value) {
        this.value = value;
    }
}
2.3 分页查询数据

使用Spring Data JPA或MyBatis进行分页查询。

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class DataService {

    @Autowired
    private DataRepository dataRepository;

    public Page<DataEntity> getDataByPage(int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return dataRepository.findAll(pageable);
    }
}
2.4 多线程导出数据

使用线程池并行处理分页查询和数据写入。

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.*;

@Service
public class ExcelExportService {

    @Autowired
    private DataService dataService;

    // 线程池配置
    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public void exportLargeDataToExcel(String filePath, int pageSize) throws IOException, InterruptedException, ExecutionException {
        // 创建 SXSSFWorkbook,设置内存中保留的行数(默认100)
        try (SXSSFWorkbook workbook = new SXSSFWorkbook(100)) {
            Sheet sheet = workbook.createSheet("Sheet1");

            // 创建表头
            Row headerRow = sheet.createRow(0);
            headerRow.createCell(0).setCellValue("ID");
            headerRow.createCell(1).setCellValue("Name");
            headerRow.createCell(2).setCellValue("Value");

            // 计算总页数
            long totalCount = dataService.getTotalCount();
            int totalPages = (int) Math.ceil((double) totalCount / pageSize);

            // 使用 CountDownLatch 等待所有线程完成
            CountDownLatch latch = new CountDownLatch(totalPages);

            // 提交任务到线程池
            for (int page = 0; page < totalPages; page++) {
                final int currentPage = page;
                executorService.submit(() -> {
                    try {
                        // 分页查询数据
                        Page<DataModel> dataPage = dataService.getDataByPage(currentPage, pageSize);
                        List<DataModel> dataList = dataPage.getContent();

                        // 写入当前页数据
                        synchronized (sheet) {
                            int startRow = currentPage * pageSize + 1; // 数据从第2行开始
                            for (int i = 0; i < dataList.size(); i++) {
                                DataModel data = dataList.get(i);
                                Row row = sheet.createRow(startRow + i);
                                row.createCell(0).setCellValue(data.getId());
                                row.createCell(1).setCellValue(data.getName());
                                row.createCell(2).setCellValue(data.getValue());
                            }
                        }
                    } finally {
                        latch.countDown(); // 任务完成
                    }
                });
            }

            // 等待所有线程完成
            latch.await();

            // 写入文件
            try (FileOutputStream outputStream = new FileOutputStream(filePath)) {
                workbook.write(outputStream);
            }

            // 清理临时文件
            workbook.dispose();
        }

        // 关闭线程池
        executorService.shutdown();
    }
}
2.5 调用导出方法

在Controller或Service中调用导出方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.concurrent.ExecutionException;

@RestController
@RequestMapping("/export")
public class ExportController {

    @Autowired
    private ExcelExportService excelExportService;

    @GetMapping("/excel")
    public String exportToExcel() throws IOException, InterruptedException, ExecutionException {
        String filePath = "large_data_export.xlsx";
        excelExportService.exportLargeDataToExcel(filePath, 10000); // 每页查询10000条数据
        return "Export successful! File saved at: " + filePath;
    }
}

三、使用EasyExcel

3.1 添加依赖

在 pom.xml 中添加 EasyExcel 依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>
3.2 定义数据模型

创建一个 Java 类表示导出的数据模型。

import com.alibaba.excel.annotation.ExcelProperty;

public class DataModel {
    @ExcelProperty("ID")
    private Long id;

    @ExcelProperty("Name")
    private String name;

    @ExcelProperty("Value")
    private Double value;

    // 构造方法、Getter 和 Setter
    public DataModel(Long id, String name, Double value) {
        this.id = id;
        this.name = name;
        this.value = value;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getValue() {
        return value;
    }

    public void setValue(Double value) {
        this.value = value;
    }
}
3.3 分页查询数据

使用 Spring Data JPA 或 MyBatis 进行分页查询。

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class DataService {

    @Autowired
    private DataRepository dataRepository;

    public Page<DataModel> getDataByPage(int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return dataRepository.findAll(pageable);
    }
}
3.4 多线程导出数据

使用线程池并行处理分页查询和数据写入。

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.WriteSheet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.*;

@Service
public class ExcelExportService {

    @Autowired
    private DataService dataService;

    // 线程池配置
    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public void exportLargeDataToExcel(HttpServletResponse response, int pageSize) throws IOException, InterruptedException, ExecutionException {
        // 设置响应头
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = "large_data_export.xlsx";
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

        // 创建 Excel 写入器
        WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").head(DataModel.class).build();

        // 计算总页数
        int totalPages = (int) Math.ceil((double) dataService.getTotalCount() / pageSize);

        // 使用 CountDownLatch 等待所有线程完成
        CountDownLatch latch = new CountDownLatch(totalPages);

        // 提交任务到线程池
        for (int page = 0; page < totalPages; page++) {
            final int currentPage = page;
            executorService.submit(() -> {
                try {
                    // 分页查询数据
                    Page<DataModel> dataPage = dataService.getDataByPage(currentPage, pageSize);
                    List<DataModel> dataList = dataPage.getContent();

                    // 写入当前页数据
                    EasyExcel.write(response.getOutputStream(), DataModel.class)
                            .sheet("Sheet1")
                            .doWrite(dataList);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown(); // 任务完成
                }
            });
        }

        // 等待所有线程完成
        latch.await();

        // 关闭线程池
        executorService.shutdown();
    }
}
3.5 Controller 调用导出方法

在 Controller 中调用导出方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

@RestController
@RequestMapping("/export")
public class ExportController {

    @Autowired
    private ExcelExportService excelExportService;

    @GetMapping("/excel")
    public void exportToExcel(HttpServletResponse response) throws IOException, InterruptedException, ExecutionException {
        excelExportService.exportLargeDataToExcel(response, 10000); // 每页查询10000条数据
    }
}

四、使用OpenCSV

4.1 添加依赖

在 pom.xml 中添加 OpenCSV 依赖:

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>5.8</version>
</dependency>
4.2 定义数据模型

创建一个 Java 类表示导出的数据模型。

public class DataModel {
    private Long id;
    private String name;
    private Double value;

    // 构造方法、Getter 和 Setter
    public DataModel(Long id, String name, Double value) {
        this.id = id;
        this.name = name;
        this.value = value;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getValue() {
        return value;
    }

    public void setValue(Double value) {
        this.value = value;
    }
}
4.3 分页查询数据

使用 Spring Data JPA 或 MyBatis 进行分页查询。

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class DataService {

    @Autowired
    private DataRepository dataRepository;

    public Page<DataModel> getDataByPage(int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return dataRepository.findAll(pageable);
    }

    public long getTotalCount() {
        return dataRepository.count();
    }
}
4.4 多线程导出数据

使用线程池并行处理分页查询和数据写入。

import com.opencsv.CSVWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Service
public class CsvExportService {

    @Autowired
    private DataService dataService;

    // 线程池配置
    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public void exportLargeDataToCsv(String filePath, int pageSize) throws IOException, InterruptedException, ExecutionException {
        // 创建 CSV 写入器
        try (CSVWriter writer = new CSVWriter(new FileWriter(filePath))) {
            // 写入表头
            writer.writeNext(new String[]{"ID", "Name", "Value"});

            // 计算总页数
            long totalCount = dataService.getTotalCount();
            int totalPages = (int) Math.ceil((double) totalCount / pageSize);

            // 使用 Future 保存每个线程的查询结果
            List<Future<List<DataModel>>> futures = new ArrayList<>();

            // 提交任务到线程池
            for (int page = 0; page < totalPages; page++) {
                final int currentPage = page;
                Future<List<DataModel>> future = executorService.submit(() -> {
                    Page<DataModel> dataPage = dataService.getDataByPage(currentPage, pageSize);
                    return dataPage.getContent();
                });
                futures.add(future);
            }

            // 合并所有线程的查询结果并写入 CSV
            for (Future<List<DataModel>> future : futures) {
                List<DataModel> dataList = future.get();
                for (DataModel data : dataList) {
                    writer.writeNext(new String[]{
                            String.valueOf(data.getId()),
                            data.getName(),
                            String.valueOf(data.getValue())
                    });
                }
            }
        }

        // 关闭线程池
        executorService.shutdown();
    }
}
4.5 Controller 调用导出方法

在 Controller 中调用导出方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.concurrent.ExecutionException;

@RestController
@RequestMapping("/export")
public class ExportController {

    @Autowired
    private CsvExportService csvExportService;

    @GetMapping("/csv")
    public String exportToCsv() throws IOException, InterruptedException, ExecutionException {
        String filePath = "large_data_export.csv";
        csvExportService.exportLargeDataToCsv(filePath, 10000); // 每页查询10000条数据
        return "Export successful! File saved at: " + filePath;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2309942.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在 Element Plus 的 <el-select> 组件中,如果需要将 <el-option> 的默认值设置为 null。 用于枚举传值

文章目录 引言轻松实现 `<el-option>` 的默认值为 `null`I 实现方式监听清空事件 【推荐】使用 v-model 绑定 null添加一个值为 null 的选项处理 null 值的显示引言 背景:接口签名规则要求空串参与,空对象不参与签名计算 // 空字符串“” 参与签名组串,null不参与签…

解码未来!安徽艾德未来智能科技有限公司荣获“GAS消费电子科创奖-产品创新奖”!

在2025年“GAS消费电子科创奖”评选中&#xff0c;安徽艾德未来智能科技有限公司提交的“讯飞AI会议耳机iFLYBUDS Pro 2”&#xff0c;在技术创新性、设计创新性、工艺创新性、智能化创新性及原创性五大维度均获得评委的高度认可&#xff0c;荣获“产品创新奖”。 这一殊荣不仅…

力扣hot100刷题——栈

文章目录 69.有效的括号题目描述思路&#xff1a;栈code 70.最小栈题目描述思路&#xff1a;双栈法code优化&#xff1a;单栈法code 71.字符串解码题目描述思路&#xff1a;栈code 73.每日温度题目描述思路&#xff1a;单调栈code 74.柱状图中最大的矩形题目描述思路&#xff1…

TMS320F28P550SJ9学习笔记2:Sysconfig 配置与点亮LED

今日学习使用Sysconfig 对引脚进行配置&#xff0c;并点亮开发板上的LED4 与LED5 我的单片机开发板平台是 LAUNCHXL_F28P55x 我是在上文描述的驱动库C2000ware官方例程example的工程基础之上进行添加功能的 该例程路径如下&#xff1a;D:\C2000Ware_5_04_00_00\driverlib\f28p…

健康养生:开启活力人生的钥匙

在快节奏的现代生活中&#xff0c;健康养生已成为我们追求美好生活的关键。它不仅关乎身体的强健&#xff0c;更与心灵的宁静息息相关。 合理饮食是健康养生的基石。多吃蔬菜、水果&#xff0c;它们富含维生素与矿物质&#xff0c;为身体提供充足养分。全谷物食品也是不错的选…

HTTP 与 HTTPS 协议:从基础到安全强化

引言 互联网的消息是如何传递的&#xff1f; 是在路由器上不断进行跳转 IP的目的是在寻址 HTTP 协议&#xff1a;互联网的基石 定义 HTTP&#xff08;英文&#xff1a;HyperText Transfer Protocol&#xff0c;缩写&#xff1a;HTTP&#xff09;&#xff0c;即超文本传输协…

【Linux】冯诺依曼体系结构-操作系统

一.冯诺依曼体系结构 我们所使用的计算机&#xff0c;如笔记本等都是按照冯诺依曼来设计的&#xff1a; 截止目前&#xff0c;我们所知道的计算机都是由一个一个的硬件组装起来的&#xff0c;这些硬件又由于功能的不同被分为了输入设备&#xff0c;输出设备&#xff0c;存储器…

mapbox进阶,使用点类型geojson加载symbol符号图层,用于标注带图标的注记,且文字居中在图标内,图标大小自适应文字

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;mapbox 从入门到精通 文章目录 一、&#x1f340;前言1.1 ☘️mapboxgl.Map 地图对象…

布隆过滤器(附带位图讲解)

提到位图&#xff0c;我们首先想到的应该是它的两面定义&#xff1a; 位图图像&#xff08;bitmap&#xff09;&#xff0c;亦称为点阵图或栅格图像&#xff0c;是由称作像素&#xff08;图片元素&#xff09;的单个点组成的。位图是指内存中连续的二进制位&#xff0c;用于对…

CC++的内存管理

目录 1、C/C内存划分 C语言的动态内存管理 malloc calloc realloc free C的动态内存管理 new和delete operator new函数和operator delete函数 new和delete的原理 new T[N]原理 delete[]的原理 1、C/C内存划分 1、栈&#xff1a;存有非静态局部变量、函数参数、返回…

【商城实战(2)】商城架构设计:从底层逻辑到技术实现

【商城实战】专栏重磅来袭&#xff01;这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建&#xff0c;运用 uniapp、Element Plus、SpringBoot 搭建商城框架&#xff0c;到用户、商品、订单等核心模块开发&#xff0c;再到性能优化、安全加固、多端适配&#xf…

USB 模块 全面解析(一)

本文是我整理的一些 USB 的学习心得&#xff0c;希望能对大家有所帮助。 文章目录 前言&#x1f352; USB 基本概述&#x1f352; USB 结构框架&#x1f349;硬件框架&#x1f349; 软件框架 &#x1f352; USB 电气信号&#x1f349; USB 硬件线路&#x1f349; 信号电平&…

xr-frame 3D Marker识别,扬州古牌坊 3D识别技术稳定调研

目录 识别物体规范 3D Marker 识别目标文件 map 生成 生成任务状态解析 服务耗时&#xff1a; 对传入的视频有如下要求&#xff1a; 对传入的视频建议&#xff1a; 识别物体规范 为提高Marker质量&#xff0c;保证算法识别效果&#xff0c;可参考Marker规范文档 Marker规…

拆一拆吉利普及高阶智驾的盲盒

吉利银河后续所有的全新和改款车型都会搭载千里浩瀚不同级别的智驾系统&#xff1b; 既然银河都标配了&#xff0c;定位更高的领克大概率也会全系标配&#xff1b; 加上极氪从去年下半年就是全系标配。 这样一来&#xff0c;就是吉利版的「全民智驾」。 一、 「千里浩瀚」&a…

2024四川大学计算机考研复试上机真题

2024四川大学计算机考研复试上机真题 2024四川大学计算机考研复试机试真题 历年四川大学计算机考研复试机试真题 在线评测&#xff1a;https://app2098.acapp.acwing.com.cn/ 分数求和 题目描述 有一分数序列&#xff1a; 2/1 3/2 5/3 8/5 13/8 21/13… 求出这个数列的前 …

基于提示驱动的潜在领域泛化的医学图像分类方法(Python实现代码和数据分析)

摘要 医学图像分析中的深度学习模型易受数据集伪影偏差、相机差异、成像设备差异等导致的分布偏移影响&#xff0c;导致在真实临床环境中诊断不可靠。领域泛化&#xff08;Domain Generalization, DG&#xff09;方法旨在通过多领域训练提升模型在未知领域的性能&#xff0c;但…

深度学习-大白话解释循环神经网络RNN

目录 一、RNN的思想 二、RNN的基本结构 网络架构 ​关键点 三、RNN的前向传播 四、RNN的挑战:梯度爆炸和梯度消失 问题分析 ​示例推导 五、LSTM:RNN的改进 核心组件 ​网络架构 3. LSTM 的工作流程 4. 数学公式总结 5. LSTM 的优缺点 ​优点 ​缺点 6. LSTM 的…

Spring统一格式返回

目录 一&#xff1a;统一结果返回 1&#xff1a;统一结果返回写法 2&#xff1a;String类型报错问题 解决方法 二&#xff1a;统一异常返回 统一异常返回写法 三&#xff1a;总结 同志们&#xff0c;今天咱来讲一讲统一格式返回啊&#xff0c;也是好久没有讲过统一格式返…

软件测试基础:功能测试知识总结

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、测试项目启动与研读需求文档 &#xff08;一&#xff09; 组建测试团队 1、测试团队中的角色 2、测试团队的基本责任 尽早地发现软件程序、系统或产品中…

wheel_legged_genesis 开源项目复现与问题记录

Reinforcement learning of wheel-legged robots based on Genesis System Requirements Ubuntu 20.04/22.04/24.04 python > 3.10 开始配置环境&#xff01; 点击releases后进入&#xff0c;下载对应最新版本的代码&#xff1a; 将下载后的代码包解压到你的自定义路径下&…