Poi导入导出百万Excel java

Java百万级别数据Excel导出 在项目开发中往往需要使用到数据的导入和导出,导入就是从Excel中导入到DB中,而导出就是从DB中查询数据然后使用POI写到Excel上。 阅读详情

前言

       项目中做报表,导入导出Excel,是常见也是不可或缺的功能,本文讲解导入多
  Excel的写法,以及导出百万的优化方案

图解代码思路

代码图解

导出多Excel工具类

package com.XXX.XXX.utils;
/**
 * @Author  windwardbird
 * @packageName  windwardbird     exportMulitExcelUtil
 * @describeOfFunction: 数据大于50万分Excel
 */
@Slf4j
@Component
public class ExportMultiExcelUtils {
  
    private static Environment environment;

    @Resource
    private Environment env;

    @PostConstruct
    public void init() {
        environment = env;   // 注入bean (自己new 出来的)
    }

    private final SimpleDateFormat format = new SimpleDateFormat("MM-dd-HH");
    private final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    private final SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd-HH");

    private static final String NEW_EXCEL_SUFFIX = ".xlsx";

    private static final String OLD_EXCEL_SUFFIX = ".xls";


    private static final Integer CURRENT_MAX_NUMBER = null==environment.getProperty("max.export.number") ?500000:env.getProperty("max.export.number"); //每个默认Excel50万


    public void ExportExcel(Map<String, Object> tempMap, Object exportExcelBase, String tableName, String model,String part) throws Exception {
        log.info("进入Excel工具类");
        List<ExportExcelBase> exportExcelBaseList = (List<ExportExcelBase>) exportExcelBase;

        List<List<Object>> excelDataResult = new ArrayList<>(); //Excel 的对应数

        List<Object> headExcelValue = new ArrayList<>();  //Excel表头

        List<Object> headExcelKey = new ArrayList<>();   //连接key

        GetExcelHeadInfo(tempMap, headExcelValue, headExcelKey);//获取Excel 表头以及连接key
        //处理数据
        ProcessingInputData(exportExcelBaseList, excelDataResult, headExcelKey);
        log.info("Excel 数据处理完毕");
        //TODO: 数据多余50万处理成多个Excel
        Integer excelTotal = excelDataResult.size(); //处理过Excel总条数
        if (excelTotal <= CURRENT_MAX_NUMBER) {
            List<List<Object>> excelDataResultTemp = new ArrayList<>();
            XSSFWorkbook wb = new XSSFWorkbook();//新版的Excel
            XSSFSheet sheet = wb.createSheet(tableName);
            excelDataResultTemp.add(headExcelValue);
            for (int j = 0; j < excelTotal; j++) {
                excelDataResultTemp.add(excelDataResult.get(j));
            }
            InsertDataToExcel(excelDataResultTemp, excelDataResultTemp.size(), sheet);
            log.info("查询数据小于50万");
            //导出Excel
            ExportExcelOfResponseStream(tableName, wb, model,part);
        } else {
            log.info("查询数据大于50万");
            int excelNumber = 0;  //分EXCEl导出 默认生成一个Excel
            int flagNum = excelTotal % CURRENT_MAX_NUMBER; // 取模看是否需要多分Excel
            if (flagNum == 0) {
                excelNumber = excelTotal / CURRENT_MAX_NUMBER;
            } else {
                excelNumber = excelTotal / CURRENT_MAX_NUMBER + 1;
            }
            for (int i = 1; i <= excelNumber; i++) {
                //构造当前Excel数据
                List<List<Object>> excelDataResultTemp = new ArrayList<>();
                XSSFWorkbook wb = new XSSFWorkbook();//新版的Excel
                XSSFSheet sheet = wb.createSheet(tableName);
                if (i == 1) {
                    //ToDo: 取50万整数据,单独加表头
                    excelDataResultTemp.add(headExcelValue);
                    for (int j = 0; j < CURRENT_MAX_NUMBER; j++) {
                        excelDataResultTemp.add(excelDataResult.get(j));
                    }
                } else {
                    excelDataResultTemp.add(headExcelValue); //添加每个Excel的表头
                    for (int j = CURRENT_MAX_NUMBER * (i - 1); j < CURRENT_MAX_NUMBER * i; j++) {

                        if (j > excelTotal) {
                            break;
                        } else if (j < excelTotal) {
                            excelDataResultTemp.add(excelDataResult.get(j));
                        }
                    }
                }
                InsertDataToExcel(excelDataResultTemp, excelDataResultTemp.size(), sheet);
                //导出Excel
                ExportExcelOfResponseStream(tableName, wb, model,part);
            }
        }
        log.info("数据转成excel处理完毕,进入生成压缩包阶段");
        //获取excel,打成zip包,根据当前的时间,放入相应的服务器路径
        String zipPath = environment.getProperty("base.path") + File.separator + model + File.separator + part + File.separator + df.format(new Date()) + File.separator;
        CompressUtil.generateFile(zipPath,"zip",tableName);

        File file = new File(zipPath);
        File[] files = file.listFiles();
        // System.gc();
        //删除excel
        for (int i = 0; i < files.length; i++) {
            if (!files[i].getName().endsWith(".zip")) {
                log.info("文件名称:{}" , files[i].getName());
                files[i].delete();
            }
        }

 
    private void ExportExcelOfResponseStream(String tableName, XSSFWorkbook wb, String model,String part) throws IOException {

        // 设置文件名(根据当前时间)
        String fileName = "" + tableName + "-" + format.format(new Date()) + "-" + SnowflakeIdUtil.nextId() + NEW_EXCEL_SUFFIX;

        //获取文件夹,如果没有则创建
        String format = df.format(new Date());
        String path = environment.getProperty("base.path") + File.separator + model + File.separator + part + File.separator  + format;
        File f = new File(path);
        if (!f.exists()) {
            f.mkdirs();
        }

        //写入excel
        FileOutputStream fileOutputStream = new FileOutputStream(path + File.separator + fileName);
        wb.write(fileOutputStream);
        fileOutputStream.flush();
        fileOutputStream.close();
        wb.close();

    }


    private void InsertDataToExcel(List<List<Object>> excelDataResult, int excelTotal, XSSFSheet
            sheet) {
        for (int i = 0; i < excelTotal; i++) {
            XSSFRow row = sheet.createRow(i);// 创建行数
            List<Object> rowData = excelDataResult.get(i);
            for (int j = 0; j < rowData.size(); j++) {
                Object cellValue = null == rowData.get(j) ? "" : rowData.get(j);
                row.createCell(j).setCellValue(String.valueOf(cellValue));
                //row.setRowStyle(cellStyle);
            }
        }
    }

    // 格式不加走默认(根据需要自己添加)
    private XSSFSheet GETExcelTypeAndName(String tableName) {
        XSSFWorkbook wb = new XSSFWorkbook();//新版的Excel
        XSSFCellStyle cellStyle = wb.createCellStyle(); //创建单元格式
        //创建单元格格式
        XSSFFont ztFont = (XSSFFont) wb.createFont();
        ztFont.setFontHeightInPoints((short) 10);    // 将字体大小设置为10px
        ztFont.setFontName("Arial");                // 将“华文行楷”字体应用到当前单元格上
       ztFont.setBoldweight( XSSFFont.BOLDWEIGHT_BOLD);//字体加粗
        cellStyle.setFont(ztFont);                    // 设置字体格式
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); //居中显示
       cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        XSSFSheet sheet = wb.createSheet(tableName);
        return sheet;
    }


    private void ProcessingInputData(List<ExportExcelBase> exportExcelBase, List<List<Object>> excelDataResult, List<Object> headExcelKey) {
        exportExcelBase.forEach(frontPartDetail -> {
                    try {
                        List<Object> headExcelData = new ArrayList<>(); //
                        Map<String, Object> frontPartMap = BeanToMap.javaBeanToMap(frontPartDetail); //当行数超过三千,就不要BeantoMap ,直接在内存根据表头构造好List<Map<String,Object>> 传入 ,效率提升50倍加
                        for (int i = 0; i < headExcelKey.size(); i++) {
                            Object tempData = frontPartMap.get(headExcelKey.get(i));
                            headExcelData.add(tempData);
                        }
                        excelDataResult.add(headExcelData);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
        );
    }


    private void GetExcelHeadInfo(Map<String, Object> tempMap, List<Object> headExcelValue, List<Object> headExcelKey) {
        for (Map.Entry<String, Object> entry : tempMap.entrySet()) {
            String key = entry.getKey(); //取数据
            Object value = entry.getValue();//表头
            headExcelValue.add(value);
            headExcelKey.add(key);
        }
    }
}




优化

导出3千可以直接用上面的工具类,倘若要导出上万或者百万的Excel?
1.上面的逻辑代码仍可以用(前提是吃硬件,时间慢)
2. 需要做的仅仅是换个接收的工具类
a .阿里的EasyExcel
b.阿帕奇的 SXSSF 替换 (XSSF)/(HSSF)

  1. pom文件的引用

阿里

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>1.1.2-beta5</version>
</dependency>

阿帕奇

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

生成zip工具可以自己写,也可以参考
https://blog.youkuaiyun.com/WindwirdBird/article/details/109273548

javaBean 转换map
https://blog.youkuaiyun.com/windwirdbird/article/details/109258678

单个SXSSFWorkbook Excel
https://blog.youkuaiyun.com/WindwirdBird/article/details/111177847

大数据量分多Excel 导出 直接用 SXSSFWorkbook
https://blog.youkuaiyun.com/WindwirdBird/article/details/111215256

POI与EasyExcel对比:Java处理Excel的性能与选型指南 在Java数据处理领域,Excel文件操作是常见需求。传统DOM解析与新兴SAX事件驱动模型代表了两种技术路线:前者如Apache POI提供完整对象模型但内存消耗大,后者如EasyExcel通过流式读取实现内存优化。从技术原理看,内存管理机制直接影响大数据量场景下的系统稳定性,特别是在云原生等资源受限环境中。通过对比测试可见,处理百万行数据时EasyExcel内存占用仅为POI的1/6,这种差异在电信话单、金融报表等海量数据场景尤为关键。对于常规业务系统,掌握两种工具的适用边界(如POI适合复杂样式修改, 阅读详情

相关推荐

数据分析项目:电商用户行为分析系统

本报告基于某电商平台用户行为数据(采样10%),通过清洗、探索性分析及多维度建模,旨在挖掘用户行为特征、商品销售规律及用户价值分层,为运营策略优化提供数据支持。原始数据字段:用户ID、商品ID、类目ID、行为类型、时间戳。长尾商品(购买量低)可考虑捆绑销售或限时折扣,提升动销率。长尾商品(购买量低)可考虑捆绑销售或限时折扣,提升动销率。,少数高活跃用户贡献大部分行为,多数用户行为次数较少。

Nervousr的博客 1703

Idea 代码存在报找不到符号

前言 话说IDEA这个开发工具已经用了好几个春秋了,没想到最近很是淘气呢,打算撂挑子了,来咱们来整顿一下这淘气的货 问题 Error:(191, 80) java: 找不到符号 符号: 方法 getListByParamWithoutPage(java.lang.Long,java.lang.Long) 位置: 类型为com.xx.xxxx.service.xxxService的变量 咦,这个报错很明显吗,为啥之前的方法不行能,给我杠上了呢,废话不多讲,咱们来修理一下它 解决方案 一步

WindwirdBird的博客 3302

i茅台APP加密参数逆向分析:MT-Device-ID与mt-v生成算法

在移动应用安全领域,参数加密是防止API滥用的重要手段。通过对通信协议的逆向分析,可以揭示加密参数的生成原理,这对理解移动应用安全机制具有重要意义。以i茅台APP为例,其关键接口使用了MT-Device-ID和mt-v两个加密参数,前者基于设备硬件信息生成,后者则通过动态签名机制确保请求时效性。这类技术广泛应用于电商、金融等需要高安全性的场景。通过抓包工具和逆向工程手段,可以还原出从设备指纹生成到动态签名的完整技术链条,其中涉及MD5、SHA256等常见哈希算法的应用。掌握这些加密参数的生成逻辑,不仅有助于

weixin_28568819的博客 321

Poi快速导出百万Excel,分多Excel导出

Poi快速导出百万Excel,分多Excel导出 直接用 package com.windwardbird.util.exportExcel; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; imp

WindwirdBird的博客 458

PCB模块化设计24——DCDC电源模块PCB布局布线设计规范

PCB模块化设计24——DCDC电源模块PCB布局布线设计规范

qq_31444421的博客 2万+

别再问“这游戏啥引擎做的”了,手把手教你用SteamDB一键查询(附实战案例)

本文详细介绍了如何使用SteamDB一键查询游戏引擎信息,包括Unity 3D、Unreal Engine等热门引擎的识别方法。通过实战案例和高级查询技巧,帮助玩家快速获取游戏技术底细,优化游戏体验和兼容性分析。

weixin_31412781的博客 827

Idea断点for循环调试

前言 作为一个开发,最高兴和痛苦的事情就是排查问题,调试代码解决问题,掌握一些技巧可以提升效率,今天就讲讲for循环断点调试的技巧 for循环断点调试 操作步骤: 1.在断点调试处加断点 2.点击断点处,鼠标右击 Idea 入门及技巧 https://blog.youkuaiyun.com/WindwirdBird/article/details/107591049 ...

WindwirdBird的博客 7653

Keil uVision5 STM32 startup_stm32f10x_md_vl.s error A3906U Malformed via file target not created..

🏆 本文收录于《全栈Bug调优(实战版)》专栏,致力于分享我在项目实战过程中遇到的各类Bug及其原因,并提供切实有效的解决方案。无论你是初学者还是经验丰富的开发者,本文将为你指引出一条更高效的Bug修复之路,助你早日登顶,迈向财富自由的梦想🚀!同时,欢迎大家关注、收藏、订阅本专栏,更多精彩内容正在持续更新中。让我们一起进步,Up!Up!Up!    备注: 部分问题/难题源自互联网,经过精心筛选和整理,结合数位十多年大厂实战经验资深大佬经验总结所得,数条可行方案供所需之人参考。

**My Coding Family** 2781

POI:EXCEL导出与追加

一、 导出excel /** * 导出excel * @param dataList 数据 * @param name 文件名称 */ public static void ExportExecl(List&lt;LinkedHashMap&lt;String,Object&gt;&gt; data...

游园拾忆 1535

微信小程序 - [wxapplib]] backgroundfetch privacy fail {“errno”:101,“errMsg”:“private_getBackgroundFetchDa

微信小程序报错之backgroundfetch privacy fail,微信小程序报错WAServiceMainContext.js:1 [wxapplib]] backgroundfetch privacy fail {“errno“:101,怎么解决?问题出现:调用wx.chooseMessageFile报错(开发者工具中正常)用户隐私协议中未声明小程序使用此功能,安卓真机调试报错:backgroundfetch privacy fail ,怎么解决?微信小程序[wxapplib]] backgrou

🏆 前端领域优质创作者 1万+

组基轨迹建模 GBTM的介绍与实现(Stata 或 R)

组基轨迹建模(Group-Based Trajectory Modeling,GBTM)(旧名称:Semiparametric mixture model)历史:由DANIELS.NAGIN提出,发表文献《Analyzing Developmental Trajectories:A Semiparametric,Group-Based Approach》GBTM能够将一群人的轨迹分类并生成数个具有代表性的运动轨迹模型,然后对每个轨迹模型进行分析,以了解人们的运动特征、生理水平和风险等级等。

三分钟热度 1万+

清除.m2下的maven仓库

前言 众所周知C盘是我们的系统盘,不得万不得已不要把别的文件放进来,影响系统运行,开发工具默认会把maven仓库加载到.m2的下面,有时依赖包甚 至高达几个 G,有没有可以在不手动切换的情况下,永远指向自己设定的位置。 烦恼的样子 解决方案: 拷一份setting.xml 文件放到 .m2目录下 蜕变的模样 效果检验 到此配置结束,妈妈再也不担心C 盘满了、卡顿,奥利给,切不切换配置全看我心情了 ...

WindwirdBird的博客 4947

【科研数据获取】根据Excel表个中的企业/公司信息批量获取经纬度坐标,并进行地图可视化

批量获取企业/公司的经纬度坐标,并进行地图可视化1 需求2 实现途径3 需求逐步实现 1 需求 在做项目的时候,老板或者项目答辩时候甲方最喜欢看到的就是可视化结果,尤其是涉及到地图可视化。很多时候会遇到企业/公司的数据,想要做地图可视化,必不可少的就是要获取它们具体地址:第一种就是像查户口一样精准一下具体的城镇街道,还有一种就是经纬度信息,前一种属于文字内容往往用于管理方面,第二种数字信息多用于数据处理与分析。 2 实现途径 获取地理信息数据,自然需要使用到地图的功能,这里直接采用百度地图的拾取坐标系统,

lys_828的博客 2337

导入导出百万数据java_Poi导入导出百万Excel数据--java编程

前言项目中做报表,导入导出Excel,是常见也是不可或缺的功能,本文讲解导入多Excel的写法,以及导出百万的优化方案图解代码思路 导出多Excel工具类package com.XXX.XXX.utils;import.XXX.ExportExcelBase;import lombok.extern.slf4j.Slf4j;import org.apache.poi.xssf.usermodel....

weixin_36130575的博客 792

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

报表技术POI导入导出复杂样式Excel和百万数据(Java代码、模板、数据)

报表技术POI导入导出含复杂样式的Excel和百万数据(Java代码、模板、数据)

欢迎朋友,我是一名十多年开发经验的新手,希望多多指教。 930

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

POI报表及百万数据导入导出方案

1、POI报表的概述 1.1 需求说明 在企业级应用开发中,Excel报表是一种最常见的报表需求。Excel报表开发一般分为两种形式:为了方便操作,基于Excel的报表批量上传数据;通过java代码生成Excel报表。 1.2 Excel的两种形式 目前世面上的Excel分为两个大的版本Excel2003和Excel2007及以上两个版本,两者之间的区别如下: Excel2003是一个特有的二进...

qqxhb 资源共享 1086

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Excel百万级数据导入导出,EasyExcel 才是 yyds

因为你所创建的book,Sheet,row,cell等在写入到Excel之前,都是存放在内存中的(这还没有算Excel的一些样式格式等等),可想而知,内存不溢出就有点不科学了!具体我没有看网上其他人的测试情况,这东西一般也很少有人愿意测试,不过这个速度对于我当时解决公司大数据的导入和导出已经足够,当然公司的业务逻辑很复杂,数据量也比较多,表的字段也比较多,导入和导出的速度会比现在测试的要慢一点,但是也在人类能接受的范围之内。在2003以前Excel的版本后缀还是.xls。它的优点是 不会报内存溢出。

竹林幽深 627

Java处理Excel表格(POI、EasyExcel)

Apache POI是用Java编写的免费开源的跨平台的Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能。

蚂蚁小哥 3974

Java报表技术POI实战

报表[forms for reporting to the higher organizations],就是向上级报告情况的表格。简单的说:报表就是用表格、图表等格式来动态显示数据,可以用公式表示为:“报表 = 多样的格式 + 动态的数据”。功能说明:整个案例我们操作用户表,做一个企业员工(用户)数据的导入导出。我们使用SpringBoot+通用mapper+vue方式搭建开发环境第一步:准备数据库,把资料文件夹下中的sql脚本直接执行《report_manager_db.sql》第二步:打开idea或Ec

fegus的博客 1941

Java_复杂Excel导入导出和转换

Java导出复杂数据到Excel: https://blog.youkuaiyun.com/hjf_1291030386/article/details/75288220 Java实现Excel转PDF的两种方法: https://blog.youkuaiyun.com/weixin_44985880/article/details/124293130?ops_request_misc=&request_id=&biz_id=102&utm_term=java%20excel%E8%BD%AC%E6%

Java后端技术栈 4876

Java使用 POI 操作Excel

  Java中常见的用来操作 Excel 的方式有2种:JXL和POI。JXL只能对 Excel进行操作,且只支持到 Excel 95-2000的版本。而POI是Apache 的开源项目,由Java编写的跨平台 Java API,可操作 Microsoft Office。借助POI,可以方便的生成数据报表,数据批量上传,数据备份等工作。 一.简单使用 1.创建Maven工程导入POI...

weixin_30460489的博客 248

eventpoi java百万级以上excel导入导出

开源地址 GitHub - beijing-penguin/eventpoi: 事件流poi处理工具 <dependency> <groupId>io.github.beijing-penguin</groupId> <artifactId>eventpoi</artifactId> <version>0.0.8</version> </dependency> 知乎文案链接 ev

DC工作室 824

java报表数据可视化

说明:使用上面的方法导出数据时,必须要提前知道要到处数据再哪一行哪一个单元格,但是如果模板一旦发生调整,那么我们的java代码必须要修改,我们可以自定义导出的引擎,有了这个引擎即使模板修改了,我们的java代码也不用修改思路:在制作模板时,在需要插入数据的位置做上标记,在导出时,对象的属性要和标记做对应,如果对应匹配一样,就把值赋值到相应位置第一步:制作模板,将模板文件添加到项目中模板中添加了username、phone、birthday等用于标记,后台通过标记判断应该填入什么数据。...

m0_63475429的博客 3867

EasyExcel百万数据量导入导出源码:一款提升数据处理效率的利器

EasyExcel百万数据量导入导出源码:一款提升数据处理效率的利器 去发现同类优质开源项目:https://gitcode.com/ 在当今信息化时代,数据已成为企业的重要资产,而对数据的处理效率则直接关系到企业的运营效率。EasyExcel百万数据量导入导出源码,正是为了解决这一痛点而诞生的一款高效工具。 项目介绍 EasyExcel 是基于 Apache POI 开发的一款开源 Java 库...

gitblog_06781的博客 755

Excel导入导出

Excel导入导出

weixin_46685542的博客 1117

Java百万级别数据Excel表导入导出实战

可以通过工具类设置导出Excel的表头样式或数据样式。本文介绍了在Java中处理百万级别数据Excel表的两种常见方案:Apache POI结合SAX解析适合自定义需求强的场景。EasyExcel适合快速实现需求的场景。通过合理使用这些工具并结合性能优化策略,可以高效地完成大数据量的Excel文件处理。此外,结合具体业务需求,我们还可以进一步扩展功能,如支持多Sheet处理、自定义模板、动态样式等,为用户提供更灵活强大的解决方案。

2301_80320652的博客 2429
上一篇: 配置多数据源
下一篇: 反射的影响
WindwardBird
博客等级 码龄7年 19粉丝 94原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值