导出:Java实现大批量数据导入导出(100W以上)

阅读文本大概需要3分钟。

来源:https://www.cnblogs.com/barrywxx/p/10700283.html

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

1. 服务器内存溢出;

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

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

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

那么如何解决呢?

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

https://www.cnblogs.com/barrywxx/p/10700283.html 

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

首先引入StringTemplate所需Jar包:

使用技术为 stringTemplate 

pom.xml:

  1. <dependency>

  2. <groupId>antlr</groupId>

  3. <artifactId>antlr</artifactId>

  4. <version>2.7.7</version>

  5. </dependency>

  6. <dependency>

  7. <groupId>org.antlr</groupId>

  8. <artifactId>stringtemplate</artifactId>

  9. <version>3.2.1</version>

    </dependency>

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

head.st可通用:

 

  1. <?xml version="1.0"?>

  2. <?mso-application progid="Excel.Sheet"?>

  3. <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"

  4. xmlns:o="urn:schemas-microsoft-com:office:office"

  5. xmlns:x="urn:schemas-microsoft-com:office:excel"

  6. xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"

  7. xmlns:html="http://www.w3.org/TR/REC-html40">

  8. <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">

  9. <Created>1996-12-17T01:32:42Z</Created>

  10. <LastSaved>2013-08-02T09:21:24Z</LastSaved>

  11. <Version>11.9999</Version>

  12. </DocumentProperties>

  13. <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">

  14. <RemovePersonalInformation/>

  15. </OfficeDocumentSettings>

  16. <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">

  17. <WindowHeight>4530</WindowHeight>

  18. <WindowWidth>8505</WindowWidth>

  19. <WindowTopX>480</WindowTopX>

  20. <WindowTopY>120</WindowTopY>

  21. <AcceptLabelsInFormulas/>

  22. <ProtectStructure>False</ProtectStructure>

  23. <ProtectWindows>False</ProtectWindows>

  24. </ExcelWorkbook>

  25. <Styles>

  26. <Style ss:ID="Default" ss:Name="Normal">

  27. <Alignment ss:Vertical="Bottom"/>

  28. <Borders/>

  29. <Font ss:FontName="宋体" x:CharSet="134" ss:Size="12"/>

  30. <Interior/>

  31. <NumberFormat/>

  32. <Protection/>

  33. </Style>

  34. </Styles>

生成大数据量Excel类:

ExcelGenerator:

 

  1. package test.exportexcel;

  2. import org.antlr.stringtemplate.StringTemplate;

  3. import org.antlr.stringtemplate.StringTemplateGroup;

  4. import test.exportexcel.bean.Row;

  5. import test.exportexcel.bean.Worksheet;

  6. import java.io.*;

  7. import java.util.ArrayList;

  8. import java.util.List;

  9. import java.util.Random;

  10. /**

  11. * 类功能描述:generator big data Excel

  12. *

  13. * @author WangXueXing create at 19-4-13 下午10:23

  14. * @version 1.0.0

  15. */

  16. public class ExcelGenerator {

  17. public static void main(String[] args) throws FileNotFoundException{

  18. ExcelGenerator template = new ExcelGenerator();

  19. template.output2();

  20. }

  21. /**

  22. * 生成数据量大的时候,该方法会出现内存溢出

  23. * @throws FileNotFoundException

  24. */

  25. public void output1() throws FileNotFoundException{

  26. StringTemplateGroup stGroup = new StringTemplateGroup("stringTemplate");

  27. StringTemplate st4 = stGroup.getInstanceOf("test/exportexcel/template/test");

  28. List<Worksheet> worksheets = new ArrayList<>();

  29. File file = new File("/home/barry/data/output.xls");

  30. PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));

  31. for(int i=0;i<30;i++){

  32. Worksheet worksheet = new Worksheet();

  33. worksheet.setSheet("第"+(i+1)+"页");

  34. List<Row> rows = new ArrayList<>();

  35. for(int j=0;j<6000;j++){

  36. Row row = new Row();

  37. row.setName1("zhangzehao");

  38. row.setName2(""+j);

  39. row.setName3(i+" "+j);

  40. rows.add(row);

  41. }

  42. worksheet.setRows(rows);

  43. worksheets.add(worksheet);

  44. }

  45. st4.setAttribute("worksheets", worksheets);

  46. writer.write(st4.toString());

  47. writer.flush();

  48. writer.close();

  49. System.out.println("生成excel完成");

  50. }

  51. /**

  52. * 该方法不管生成多大的数据量,都不会出现内存溢出,只是时间的长短

  53. * 经测试,生成2400万数据,2分钟内,4.5G大的文件,打开大文件就看内存是否足够大了

  54. * 数据量小的时候,推荐用JXLS的模板技术生成excel文件,谁用谁知道,大数据量可以结合该方法使用

  55. * @throws FileNotFoundException

  56. */

  57. public void output2() throws FileNotFoundException{

  58. long startTimne = System.currentTimeMillis();

  59. StringTemplateGroup stGroup = new StringTemplateGroup("stringTemplate");

  60. //写入excel文件头部信息

  61. StringTemplate head = stGroup.getInstanceOf("test/exportexcel/template/head");

  62. File file = new File("/home/barry/data/output.xls");

  63. PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));

  64. writer.print(head.toString());

  65. writer.flush();

  66. int sheets = 400;

  67. //excel单表最大行数是65535

  68. int maxRowNum = 60000;

  69. //写入excel文件数据信息

  70. for(int i=0;i<sheets;i++){

  71. StringTemplate body = stGroup.getInstanceOf("test/exportexcel/template/body");

  72. Worksheet worksheet = new Worksheet();

  73. worksheet.setSheet(" "+(i+1)+" ");

  74. worksheet.setColumnNum(3);

  75. worksheet.setRowNum(maxRowNum);

  76. List<Row> rows = new ArrayList<>();

  77. for(int j=0;j<maxRowNum;j++){

  78. Row row = new Row();

  79. row.setName1(""+new Random().nextInt(100000));

  80. row.setName2(""+j);

  81. row.setName3(i+""+j);

  82. rows.add(row);

  83. }

  84. worksheet.setRows(rows);

  85. body.setAttribute("worksheet", worksheet);

  86. writer.print(body.toString());

  87. writer.flush();

  88. rows.clear();

  89. rows = null;

  90. worksheet = null;

  91. body = null;

  92. Runtime.getRuntime().gc();

  93. System.out.println("正在生成excel文件的 sheet"+(i+1));

  94. }

  95. //写入excel文件尾部

  96. writer.print("</Workbook>");

  97. writer.flush();

  98. writer.close();

  99. System.out.println("生成excel文件完成");

  100. long endTime = System.currentTimeMillis();

  101. System.out.println("用时="+((endTime-startTimne)/1000)+"秒");

  102. }

  103. }

定义JavaBean:

WorkSheet.java:

  1. package test.exportexcel.bean;

  2. import java.util.List;

  3. /**

  4. * 类功能描述:Excel sheet Bean

  5. *

  6. * @author WangXueXing create at 19-4-13 下午10:21

  7. * @version 1.0.0

  8. */

  9. public class Worksheet {

  10. private String sheet;

  11. private int columnNum;

  12. private int rowNum;

  13. private List<Row> rows;

  14. public String getSheet() {

  15. return sheet;

  16. }

  17. public void setSheet(String sheet) {

  18. this.sheet = sheet;

  19. }

  20. public List<Row> getRows() {

  21. return rows;

  22. }

  23. public void setRows(List<Row> rows) {

  24. this.rows = rows;

  25. }

  26. public int getColumnNum() {

  27. return columnNum;

  28. }

  29. public void setColumnNum(int columnNum) {

  30. this.columnNum = columnNum;

  31. }

  32. public int getRowNum() {

  33. return rowNum;

  34. }

  35. public void setRowNum(int rowNum) {

  36. this.rowNum = rowNum;

  37. }

  38. }

Row.java:

  1. package test.exportexcel.bean;

  2. /**

  3. * 类功能描述:Excel row bean

  4. *

  5. * @author WangXueXing create at 19-4-13 下午10:22

  6. * @version 1.0.0

  7. */

  8. public class Row {

  9. private String name1;

  10. private String name2;

  11. private String name3;

  12. public String getName1() {

  13. return name1;

  14. }

  15. public void setName1(String name1) {

  16. this.name1 = name1;

  17. }

  18. public String getName2() {

  19. return name2;

  20. }

  21. public void setName2(String name2) {

  22. this.name2 = name2;

  23. }

  24. public String getName3() {

  25. return name3;

  26. }

  27. public void setName3(String name3) {

  28. this.name3 = name3;

  29. }

  30. }

另附实现源码:

https://files.cnblogs.com/files/barrywxx/exportexcel.zip

往期精彩

01 漫谈发版哪些事,好课程推荐

02 Linux的常用最危险的命令

03 精讲Spring&nbsp;Boot—入门+进阶+实例

04 优秀的Java程序员必须了解的GC哪些

05 互联网支付系统整体架构详解

关注我

每天进步一点点

喜欢!在看☟

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值