Excel 文件的生成与下载
一、Apache 开源框架 poi、jxl 的缺陷
两者都存在生成 excel 文件不够简单优雅快速的问题。而且它们都还存在一个严重的问题,那就是非常耗内存,严重时会导致内存溢出。POI 虽然目前来说,是 excel 解析框架中被使用最广泛的,但这个框架并不完美。为什么这么说呢?
开发者们大部分使用 POI,都是使用其 userModel 模式。而 userModel 的好处是上手容易使用简单,随便拷贝个代码跑一下,剩下就是写业务转换了,虽然转换也要写上百行代码,但是还是可控的。
然而 userModel 模式最大的问题是在于,对内存消耗非常大,一个几兆的文件解析甚至要用掉上百兆的内存。现实情况是,很多应用现在都在采用这种模式,之所以还正常在跑是因为并发不大,并发上来后,一定会OOM或者频繁的FULL GC。
二、阿里的 EasyExcel
官方对其的简介是:快速、简单避免OOM的java处理Excel工具。
三、EasyExcel 解决了什么
- 传统 Excel 框架,如 Apache poi、jxl 都存在内存溢出的问题;
- 传统 excel 开源框架使用复杂、繁琐;
- EasyExcel 底层还是使用的 poi,但是做了很多优化,比如修复了并发情况下的一些 bug,具体修复细节,可阅读官方文档 https://github.com/alibaba/easyexcel
四、pom 依赖
<!--alibaba easyexcel-->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>1.1.2-beta5</version>
</dependency>
五、代码示例
@Test
public void writeExcel() throws Exception {// 文件输出位置OutputStream out = new FileOutputStream("d:/test.xlsx");ExcelWriter writer = EasyExcelFactory.getWriter(out);// 写仅有一个 Sheet 的 Excel 文件, 此场景较为通用Sheet sheet = new Sheet(1, 0, WriteModel.class);// 第一个 sheet 名称sheet.setSheetName("first sheet");// 写数据到 Writer 上下文中// 入参1: 创建要写入的模型数据// 入参2: 要写入的目标 sheetwriter.write(createModelList(), sheet);// 将上下文中的最终 outputStream 写入到指定文件中writer.finish();// 关闭流out.close();
}
上面这段示例代码中,有两点很重要:
①WriteModel 这个对象就是要写入 Excel 的数据模型对象(表头 head,以及每个单元格内的数据顺序下文说明)
②创建需要写入的数据集,(正常业务中,这块都是从数据库中查询出来的)
1️⃣createModelList
private List<WriteModel> createModelList() {List<WriteModel> writeModels = new ArrayList<>();for (int i = 0; i < 100; i++) {WriteModel writeModel = WriteModel.builder().name("test" + i).password("123456").age(i + 1).build();writeModels.add(writeModel);}return writeModels;
}
2️⃣WriteModel
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class WriteModel extends BaseRowModel {@ExcelProperty(value = "姓名", index = 0)private String name;@ExcelProperty(value = "密码", index = 1)private String password;@ExcelProperty(value = "年龄", index = 2)private Integer age;
}
ExayExcel 提供注解的方式,来方便的定义 Excel 需要的数据模型:
①首先,定义的写入模型必须要继承自 BaseRowModel.java;
②通过 @ExcelProperty 注解来指定每个字段的列名称,以及下标位置
六、️动态生成 Excel 内容
上面的例子是基于注解的,也就是说表头 head以及内容都是写死的,换句话说,定义好了一个数据模型,那么,生成的 Excel 文件也就是只能遵循这种模型来了。但是,实际业务中可能会存在动态变化的需求,要怎么做?
@Testpublic void writeExcel() throws Exception {// 文件输出位置OutputStream out = new FileOutputStream("d:/dynamic.xlsx");ExcelWriter writer = EasyExcelFactory.getWriter(out);// 动态添加表头,适用一些表头动态变化的场景Sheet sheet = new Sheet(1, 0);sheet.setSheetName("first sheet");// 创建一个表格,用于 Sheet 中使用Table table = new Table(1);//自定义表格样式table.setTableStyle(createTableStyle());// 无注解的模式,动态添加表头table.setHead(createTestListStringHead());// 写数据writer.write1(createDynamicModelList(), sheet, table);//可以通过 merge()方法来合并单元格//注意下标是从 0 开始的,也就是说合并了第六行到第七行,其中的第一列到第五列writer.merge(5, 6, 0, 4);// 将上下文中的最终 outputStream 写入到指定文件中writer.finish();// 关闭流out.close();}
1️⃣无注解模式,动态添加表头,也可自由组合复杂表头,代码如下:
public static List<List<String>> createTestListStringHead() {// 模型上没有注解,表头数据动态传入List<List<String>> head = new ArrayList<List<String>>();List<String> headCoulumn1 = new ArrayList<String>();List<String> headCoulumn2 = new ArrayList<String>();List<String> headCoulumn3 = new ArrayList<String>();List<String> headCoulumn4 = new ArrayList<String>();List<String> headCoulumn5 = new ArrayList<String>();headCoulumn1.add("第一列");headCoulumn1.add("第一列");headCoulumn1.add("第一列");headCoulumn2.add("第一列");headCoulumn2.add("第一列");headCoulumn2.add("第一列");headCoulumn3.add("第二列");headCoulumn3.add("第二列");headCoulumn3.add("第二列");headCoulumn4.add("第三列");headCoulumn4.add("第三列2");headCoulumn4.add("第三列2");headCoulumn5.add("第四列");headCoulumn5.add("第4列");headCoulumn5.add("第5列");head.add(headCoulumn1);head.add(headCoulumn2);head.add(headCoulumn3);head.add(headCoulumn4);head.add(headCoulumn5);return head;}
2️⃣创建动态数据,注意这里的数据类型是 Object:
private List<List<Object>> createDynamicModelList() {//所有行数据List<List<Object>> rows = new ArrayList<>();for (int i = 0; i < 100; i++) {//一行数据List<Object> row = new ArrayList<>();row.add("第" + i+"行");row.add(Long.valueOf(187837834L + i));row.add(Integer.valueOf(2233 + i));row.add("NMB");row.add("CBF");rows.add(row);}return rows;}
3️⃣自定义表头以及内容样式
public static TableStyle createTableStyle() {TableStyle tableStyle = new TableStyle();// 设置表头样式Font headFont = new Font();// 字体是否加粗headFont.setBold(true);// 字体大小headFont.setFontHeightInPoints((short) 12);// 字体headFont.setFontName("楷体");tableStyle.setTableHeadFont(headFont);// 背景色tableStyle.setTableHeadBackGroundColor(IndexedColors.BLUE);// 设置表格主体样式Font contentFont = new Font();contentFont.setBold(true);contentFont.setFontHeightInPoints((short) 12);contentFont.setFontName("黑体");tableStyle.setTableContentFont(contentFont);tableStyle.setTableContentBackGroundColor(IndexedColors.GREEN);return tableStyle;}
七、 自定义处理
对于更复杂的处理,EasyExcel 预留了 WriterHandler 接口来,允许你自定义处理代码:
接口中定义了三个方法:
- sheet(): 在创建每个 sheet 后自定义业务逻辑处理;
- row(): 在创建每个 row 后自定义业务逻辑处理;
- cell(): 在创建每个 cell 后自定义业务逻辑处理;
我们实现了该接口后,编写自定义逻辑处理代码,然后调用 getWriterWithTempAndHandler() 静态方法获取 ExcelWriter 对象时,传入 WriterHandler 的实现类即可。
例:
ExcelWriter writer = EasyExcelFactory
.getWriterWithTempAndHandler(null, out, ExcelTypeEnum.XLSX, true, new MyWriterHandler());
八、Web 下载示例代码
public class Down {@GetMapping("/a.htm")public void cooperation(HttpServletRequest request, HttpServletResponse response) {ServletOutputStream out = response.getOutputStream();ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX, true);String fileName = new String(("UserInfo " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())).getBytes(), "UTF-8");Sheet sheet1 = new Sheet(1, 0);sheet1.setSheetName("第一个sheet");writer.write0(getListString(), sheet1);writer.finish();response.setContentType("multipart/form-data");response.setCharacterEncoding("utf-8");response.setHeader("Content-disposition", "attachment;filename="+fileName+".xlsx");out.flush();}}
九、需要注意的点
1️⃣写入大数据时,需分片。比如说,从数据库中查询出数据量较大时,需要在业务层做分片处理,也就是需要分多次查询,再写入,防止内存溢出 OOM。
2️⃣Excel 最大行数问题。
Excel 03、07 版本均有行数、列数的限制:
版本 最大行 最大列
Excel 2003 65536 256
Excel 2007 1048576 16384
csv 由于是文本文件,实际上没有最大行数的限制,但是用 Excel 客户端打开还是多了不显示。也就是说,如果想写入更多的行数是不行的,强行这么做,程序会报类似如下异常:
Invalid row number (1048576) outside allowable range (0..1048575)
如何解决呢?
分多个 Excel 文件写入;
同一个 Excel 文件,分多个 Sheet 写入。
Excel 文件的生成与下载相关推荐
- 使用Excel文件批量生成Codabar码
Codabar(库德巴码)是由Monarch Marking Systems在1972年研制的条形码.它是在"2 of 5"后早期阶段引入的条形码.广泛用于需要序列号的领域,如血库 ...
- 通过Excel文件批量生成Code 39扩展码
code39码是条形码的一种,编码简单.能够对任意长度的数据进行编码.支持设备广泛,所以code39码是最常用的条形码之一.code39码在条码打印软件中有两种表现类型:标准code39码和支持字符更 ...
- 自动更新开奖数据的excel文件,供大家下载
自动更新开奖数据的excel文件,供大家下载 2010-03-14 20:22 228492人阅读打印来源:乐彩网 作者:eren 很多人拥有自制excel电子表格,常要更新最基本的开奖信息.如有多期 ...
- 使用阿里的easyexcel 来实现excel文件的读取和下载
使用阿里的easyexcel 来实现excel文件的读取和下载 1.首先下载maven依赖 <dependency><groupId>com.alibaba</group ...
- 获取jqGrid中的所有数据导出并生成Excel文件流供用户下载(post请求实现文件下载)...
最近有一个需求是: 将jqGrid表格中的数据生成报表Excel文件返回给用户. 我的想法是获取jqGrid中的数据然后生成json数据,传给后端,生成文件流,响应到前端,保存为excel文件. aj ...
- java后台生成的Excel文件并通过浏览器下载
java后台生成Excel文件需要引入poi, 以下是poi的pom可以引入自己的项目里面去 <dependency><groupId>org.apache.poi</g ...
- javaSE中的数据导出到Excel表、javaEE中后台生成Excel文件到浏览器端下载
整个项目中导出数据到.Excel的源码 import java.io.BufferedOutputStream; import java.io.FileInputStream; import java ...
- springmvc html excel文件,springmvc生成文件(excel、pdf...)和文件上传
生成文件 以下以下载excel文件为例,如有其它需要可自定义实现类继承相应springmvc提供的试图接口即可. 如生成Excel则继承AbstractExcelView,生成PDF则继承Abstra ...
- java 生成操作excel文件_Java生成和操作Excel文件
AVA EXCEL API:是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容.创建新的Excel文件.更新已经存在的Excel文件.使用该API非Windows操作系统也可以通过纯 ...
最新文章
- 合肥工业大学—SQL Server数据库实验一:数据库的创建和删除
- R语言dplyr包recode函数、recode_factor函数数值或因子替换实战
- Android测试之Monkey初体验
- 南外计算机课,南外小升初,怎么考?
- script的加载方式与执行
- jmeter constant timer 如何添加_阿里巴巴在开源压测工具 JMeter 上的实践和优化
- CodeForces 486C Palindrome Transformation 贪心+抽象问题本质
- JacksonUtils Jackson的JSON序列化反序列化
- python爬虫学习之页面登陆
- 在ASP.NET Identity 2.0中使用声明(Claims)实现用户组
- 虚拟机安装菜鸟教程(1)—CentOS6.4系统VMware安装及配置详细教程
- BZOJ 1041 圆上的整点 数学
- Appium框架中Android下EditText内容清除
- 给MTL库添加求行列式值
- Java API II
- vue 时间方法(yyyy-mmmm-dddd hh:mm:ss)
- app做好后如何上线_手机APP开发后如何上架?
- 基于Pytorch实现自建数据库的深度神经网络模型案例
- 微信壁纸小程序(SpringBoot后台V1.3.0发布)
- three.js绘制墙体,通过不规则路径生成墙体,3D墙体绘制
热门文章
- linux qt jom,Qt Creator 使用技巧之提高编译速度【使用jom参数】
- 钣金展开软件,包能用,无需注册,无需费用,
- 笔记-lxf官网面向对象高级编程
- 天涯明月刀服务器维护了,10月21日服务器例行维护公告
- 网页后缀html、htm、shtml、shtm有什么区别?
- 详解国产音频DAC芯片的工作原理及应用
- ArrayList集合的常用方法
- 浏览器打印,Chrome网页打印中的宽度控制
- 上海交通大学计算机专业培养方案,上海交通大学计算机科学与技术专业本科培养计划...
- Java实现--基于服务器的多用户聊天室