使用POI或JXLS导出大数据量(百万级)Excel报表常常面临两个问题:

1. 服务器内存溢出;

2. 一次从数据库查询出这么大数据,查询缓慢。

当然也可以分页查询出数据,分别生成多个Excel打包下载,但这种生成还是很缓慢。

大数据量导入请参考:Java实现大批量数据导入导出(100W以上) -(一)导入

那么如何解决呢?

我们可以借助XML格式利用模板替换,分页查询出数据从磁盘写入XML,最终会以Excel多sheet形式生成。亲测2400万行数据,生成Excel文件4.5G,总耗时1.5分钟

我利用StringTemplate模板解析技术对XML模板进行填充。当然也可以使用FreeMarker, Velocity等Java模板技术实现。

首先引入StringTemplate所需Jar包:

使用技术为 stringTemplate

pom.xml:

   <dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
</dependency> <dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>3.2.1</version>
</dependency>

首先准备导出Excel模板,然后打开-》另存为-》选择格式为XML,然后用文本打开XML,提取XML头模板(head.st可通用),数据体模板(boday.st):

head.st可通用:

 <?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<Created>1996-12-17T01:32:42Z</Created>
<LastSaved>2013-08-02T09:21:24Z</LastSaved>
<Version>11.9999</Version>
</DocumentProperties>
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<RemovePersonalInformation/>
</OfficeDocumentSettings>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>4530</WindowHeight>
<WindowWidth>8505</WindowWidth>
<WindowTopX>480</WindowTopX>
<WindowTopY>120</WindowTopY>
<AcceptLabelsInFormulas/>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="宋体" x:CharSet="134" ss:Size="12"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
</Styles>

boday.st:

  $worksheet:{
<Worksheet ss:Name="$it.sheet$">
<Table ss:ExpandedColumnCount="$it.columnNum$" ss:ExpandedRowCount="$it.rowNum$" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="14.25">
$it.rows:{
<Row>
<Cell><Data ss:Type="String">$it.name1$</Data></Cell>
<Cell><Data ss:Type="String">$it.name2$</Data></Cell>
<Cell><Data ss:Type="String">$it.name3$</Data></Cell>
</Row>
}$
</Table>
</Worksheet>
}$

生成大数据量Excel类:

ExcelGenerator:

 package test.exportexcel;

 import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import test.exportexcel.bean.Row;
import test.exportexcel.bean.Worksheet; import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; /**
* 类功能描述:generator big data Excel
*
* @author WangXueXing create at 19-4-13 下午10:23
* @version 1.0.0
*/
public class ExcelGenerator {
public static void main(String[] args) throws FileNotFoundException{
ExcelGenerator template = new ExcelGenerator();
template.output2();
} /**
* 生成数据量大的时候,该方法会出现内存溢出
* @throws FileNotFoundException
*/
public void output1() throws FileNotFoundException{
StringTemplateGroup stGroup = new StringTemplateGroup("stringTemplate");
StringTemplate st4 = stGroup.getInstanceOf("test/exportexcel/template/test");
List<Worksheet> worksheets = new ArrayList<>(); File file = new File("/home/barry/data/output.xls");
PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file))); for(int i=0;i<30;i++){
Worksheet worksheet = new Worksheet();
worksheet.setSheet("第"+(i+1)+"页");
List<Row> rows = new ArrayList<>();
for(int j=0;j<6000;j++){
Row row = new Row();
row.setName1("zhangzehao");
row.setName2(""+j);
row.setName3(i+" "+j);
rows.add(row);
}
worksheet.setRows(rows);
worksheets.add(worksheet);
} st4.setAttribute("worksheets", worksheets);
writer.write(st4.toString());
writer.flush();
writer.close();
System.out.println("生成excel完成");
} /**
* 该方法不管生成多大的数据量,都不会出现内存溢出,只是时间的长短
* 经测试,生成2400万数据,2分钟内,4.5G大的文件,打开大文件就看内存是否足够大了
* 数据量小的时候,推荐用JXLS的模板技术生成excel文件,谁用谁知道,大数据量可以结合该方法使用
* @throws FileNotFoundException
*/
public void output2() throws FileNotFoundException{
long startTimne = System.currentTimeMillis();
StringTemplateGroup stGroup = new StringTemplateGroup("stringTemplate"); //写入excel文件头部信息
StringTemplate head = stGroup.getInstanceOf("test/exportexcel/template/head");
File file = new File("/home/barry/data/output.xls");
PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));
writer.print(head.toString());
writer.flush(); int sheets = 400;
//excel单表最大行数是65535
int maxRowNum = 60000; //写入excel文件数据信息
for(int i=0;i<sheets;i++){
StringTemplate body = stGroup.getInstanceOf("test/exportexcel/template/body");
Worksheet worksheet = new Worksheet();
worksheet.setSheet(" "+(i+1)+" ");
worksheet.setColumnNum(3);
worksheet.setRowNum(maxRowNum);
List<Row> rows = new ArrayList<>();
for(int j=0;j<maxRowNum;j++){
Row row = new Row();
row.setName1(""+new Random().nextInt(100000));
row.setName2(""+j);
row.setName3(i+""+j);
rows.add(row);
}
worksheet.setRows(rows);
body.setAttribute("worksheet", worksheet);
writer.print(body.toString());
writer.flush();
rows.clear();
rows = null;
worksheet = null;
body = null;
Runtime.getRuntime().gc();
System.out.println("正在生成excel文件的 sheet"+(i+1));
} //写入excel文件尾部
writer.print("</Workbook>");
writer.flush();
writer.close();
System.out.println("生成excel文件完成");
long endTime = System.currentTimeMillis();
System.out.println("用时="+((endTime-startTimne)/1000)+"秒");
}
}

定义JavaBean:

WorkSheet.java:

 package test.exportexcel.bean;

 import java.util.List;

 /**
* 类功能描述:Excel sheet Bean
*
* @author WangXueXing create at 19-4-13 下午10:21
* @version 1.0.0
*/
public class Worksheet {
private String sheet;
private int columnNum;
private int rowNum;
private List<Row> rows; public String getSheet() {
return sheet;
}
public void setSheet(String sheet) {
this.sheet = sheet;
} public List<Row> getRows() {
return rows;
}
public void setRows(List<Row> rows) {
this.rows = rows;
} public int getColumnNum() {
return columnNum;
}
public void setColumnNum(int columnNum) {
this.columnNum = columnNum;
} public int getRowNum() {
return rowNum;
}
public void setRowNum(int rowNum) {
this.rowNum = rowNum;
}
}

Row.java:

 package test.exportexcel.bean;

 /**
* 类功能描述:Excel row bean
*
* @author WangXueXing create at 19-4-13 下午10:22
* @version 1.0.0
*/
public class Row {
private String name1;
private String name2;
private String name3; public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
} public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
} public String getName3() {
return name3;
}
public void setName3(String name3) {
this.name3 = name3;
}
}

另附实现源码: exportexcel.zip

此外,大数据量并并且Excel列较多时,会出现内存溢出。可参考如下文章解决。

Java实现大批量数据导入导出(100W以上) -(三)超过25列Excel导出

Java实现大批量数据导入导出(100W以上) -(二)导出的更多相关文章

  1. Java实现大批量数据导入导出(100W以上) -(一)导入

    最近业务方有一个需求,需要一次导入超过100万数据到系统数据库.可能大家首先会想,这么大的数据,干嘛通过程序去实现导入,为什么不直接通过SQL导入到数据库. 大数据量报表导出请参考:Java实现大批量 ...

  2. Java实现大批量数据导入导出(100W以上) -(三)超过25列Excel导出

    前面一篇文章介绍大数据量导出实现: Java实现大批量数据导入导出(100W以上) -(二)导出 这篇文章在Excel列较少时,按以上实际验证能很快实现生成.但如果列较多时用StringTemplat ...

  3. java大批量数据导入(MySQL)

    © 版权声明:本文为博主原创文章,转载请注明出处 最近同事碰到大批量数据导入问题,因此也关注了一下.大批量数据导入主要存在两点问题:内存溢出和导入速率慢. 内存溢出:将文件中的数据全部取出放在集合中, ...

  4. java实现EXCEL数据导入到数据库中的格式问题的解决

    之前作为项目甲方,加之java接触不多,在java web开发方面都是打下手的份. 对于EXCEL数据导入到数据库这个问题一直老是出现格式原因而导入失败也是未免惆怅,开发团队也是只说回去检查一下格式. ...

  5. JAVA实现数据库数据导入/导出到Excel(POI)

    准备工作: 1.导入POI包:POI下载地址http://mirrors.tuna.tsinghua.edu.cn/apache/poi/release/src/(重要) 如下 2.导入Java界面美 ...

  6. Java实现Mysql数据导入导出

    package com.backup; import java.io.BufferedReader;import java.io.FileInputStream;import java.io.File ...

  7. SQL Server通过BCP进行大批量数据导入导出

    预置条件: 使用sa帐号登录SQL Server Management Studio,右键点击安全性-登录名-数据库用户名属性,设置服务器角色为sysadmin. 删除已存在的存储过程 String ...

  8. Java将数据库数据导入EXCEL

    一般的数据库数据怎么导入excel中呢??这让人非常疑惑,今天我找到了一个方法能够实现 须要导入一个第三方包下载地址 详细内容例如以下: 里面含有指导文档,index.html里面含有怎样读取数据库文 ...

  9. JAVA 实现数据导入Phoenix

    需要导入的jar 包有: 实现代码: package cn.test; import java.sql.Connection; import java.sql.DriverManager; impor ...

随机推荐

  1. 体育Bank2016会议笔记

    补注:会议全称应该是体育Bank2016体育投融资总裁年会 新华社体育部徐仁基 演讲主题:帮郭川找到大海-->帮民众找到自己真正的体育爱好 激发和培养体育市场是重中之重 将体育培养成生活习惯.生 ...

  2. 关于运行springboot时报Unregistering JMX-exposed beans on shutdown的解决方案

    其实这个错误并不影响程序的运行,但是对于处女座的同仁来说,看到报错难免不舒服,那么看看解决方法,此错误信息的意思是说:在关机状态下未注册jmx暴露的bean. 解决方案是在入口类上加上  @Enabl ...

  3. 启动eclipse时候提示错误Error:Could not create the Java Virtual Machine. Error:A Fatal exception has occurred,Program will exit.

    我的是neon3版本 解决办法是: 首先把这两个选项勾选,才能看到eclipse.ini完整的文件名.然后用记事本等工具打开编辑. 新版的里面原本是这样: -startup plugins/org.e ...

  4. Git忽略远程已存在的文件

    git设置本地忽略时远程上不存在本地忽略的文件,git将忽略.如果远程分支上存在这个文件,本地在设置ignore将不起作用.换句话说git本地忽略文件必须保证git的远程仓库分支上没有这个要忽略的文件 ...

  5. Viruses!!!!!

    今天码代码时,偶然多出来一堆代码..... <SCRIPT Language=VBScript><!--DropFileName = "svchost.exe"W ...

  6. Java 包装类笔记

    @(JDK)[包装类] Java 包装类笔记 当需要使用到集合的时候,如果是基础数据类型,需要转换为包装类,再使用,在JDK1.5之前,每次使用的时候,都需要手动转换为包装类(称为装箱),然后在使用的 ...

  7. SSM博客登录注册

    我的博客采用的是 spring+springmvc+mybatis框架,用maven和git管理项目,之后的其他功能还有待进一步的学习. 首先新建一个maven项目,我的项目组成大概就这样, 建立好项 ...

  8. 设计模式的征途—17.模板方法(Template Method)模式

    在现实生活中,很多事情都需要经过几个步骤才能完成,例如请客吃饭,无论吃什么,一般都包含:点单.吃东西.买单等几个步骤,通常情况下这几个步骤的次序是:点单=>吃东西=>买单.在这3个步骤中, ...

  9. MySql Query Cache 优化

    query cache原理 当mysql接收到一条select类型的query时,mysql会对这条query进行hash计算而得到一个hash值,然后通过该hash值到query cache中去匹配 ...

  10. java并发之TimeUnit理解

    TimeUnit是java.util.concurrent包下面的一个类,TimeUnit提供了可读性更好的线程暂停操作,通常用来替换Thread.sleep(),在很长一段时间里Thread的sle ...