文章目录
- [一、spring boot 操作excel](#一、spring boot 操作excel)
-
- [1. 技术选型](#1. 技术选型)
-
- [1.1 EasyExcel](#1.1 EasyExcel)
- [1.2 POI](#1.2 POI)
- 二、EasyExcel使用
-
- [0. 工作中使用总结](#0. 工作中使用总结)
- [1. maven 引入](#1. maven 引入)
- [2. demo1:excel写入文件](#2. demo1:excel写入文件)
- [3. demo2:SpringBoot项目中集成EasyExcel实现Excel文件的下载](#3. demo2:SpringBoot项目中集成EasyExcel实现Excel文件的下载)
- [4. demo3:SpringBoot项目中集成EasyExcel实现Excel文件导入(同步处理数据)](#4. demo3:SpringBoot项目中集成EasyExcel实现Excel文件导入(同步处理数据))
-
- [4.1 AnalysisEventListener](#4.1 AnalysisEventListener)
- 三、工作常用参考
-
- [1. easyexcel 上传返回结果给前端(返回成功/失败数量及原因)](#1. easyexcel 上传返回结果给前端(返回成功/失败数量及原因))
- [2. easyexcel 导入数据校验](#2. easyexcel 导入数据校验)
- 四、参考
一、spring boot 操作excel
1. 技术选型
java本身并不支持读取excel,所有读取excel需要借助一些框架。目前有几种方式:
- Apache POI
- easyexcel
POI提供的对Excel操作不仅消耗内存而且解压时完全在内存中完成,内存消耗非常大。
- easyExcel的确比poi方便,但是它的读需要编写监听器
- 建议大数据用easyExcel,因为大数据时poi对于内存消耗非常大
- 由于apache poi和jxl,excelPOI都有一个严重的问题,就是非常消耗内存,特别处理数据量多时,速度慢并且时有异常发生,所以改用由阿里研发的easyExcel更可靠一些,它的官方建议对于1000行以内的采用原来poi的写法一次读写,但于1000行以上的数据,有用了一行行进行解析的方案,这样避免了内存的溢出。
- EasyExcel扩展功能很多,且Api式调用真的轻松很多
1.1 EasyExcel
官方网站: https://yuque.com/easyexcel
https://github.com/alibaba/easyexcel
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
EasyExcel能减少内存占用的原因是它没有将文件一次性加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
EasylExcel的特点:
1、poi和jxl非常的消耗内存,并发上来后会OOM或是JVM频繁的full gc。
2、EasylExcel对poi进行了封装,使用简单,节省内存。
3、EasyExcel没有把文件数据一次性全部加载到内存中,而是从磁盘一行一行读取数据,逐个解析,并将解析结果以观察者的模式通知处理(AnalysisEventListener)。
1.2 POI
POI是Apache提供的开源代码库,这个代码库用来提供Java客户端对Microsoft Office格式文件的读写操作。
POI为"Poor Obfuscation Implementation"的首字母缩写,意为"简洁版的模糊实现"。
POI有五种结构
HSSF------提供读写Microsoft Excel(2003)格式档案功能
XSSF------提供读写Microsoft Excel OOXML(2007-今)格式档案的功能
HWPF------提供读写Microsoft Word格式档案的功能
HSLF------提供读写Microsoft PPT格式档案功能
HDGF------提供读写Microsoft Visio格式档案的功能
二、EasyExcel使用
0. 工作中使用总结
- 目前读取excel文件不再需要指定ExcelTypeEnum,即excel的版本,会自动处理
- 之前创建ExcelReader都是自己new,现在是通过EasyExcelFactory创建,更加简单和具备通用性。
- 之前每解析一行的回调的invoke()方法,通用对象Object是list集合,目前是HashMap集合。
1. maven 引入
repo仓库搜索 关键字 EasyExcel ,使用最新版本。
java
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.3</version>
</dependency>
2. demo1:excel写入文件
java
@HeadRowHeight(20) // 表头行高
@ColumnWidth(15) // 表头行宽
@Data
public class DemoData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/**
* 忽略这个字段
*/
@ExcelIgnore
private String ignore;
}
java
public class ExcelServiceTest {
/**
* 最简单的写
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 直接写即可
*/
@Test
public void simpleWrite1() {
// 写法1
String fileName = "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
}
@Test
public void simpleWrite2(){
// 写法2
String fileName = "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
excelWriter.write(data(), writeSheet);
} finally {
// 千万别忘记finish 会帮忙关闭流
if (excelWriter != null) {
excelWriter.finish();
}
}
}
private List<DemoData> data() {
List<DemoData> list = new ArrayList<DemoData>();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
data.setString("字符串" + i);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
}
3. demo2:SpringBoot项目中集成EasyExcel实现Excel文件的下载
SpringBoot项目中集成EasyExcel实现Excel文件的下载
参考URL: https://blog.csdn.net/riemann_/article/details/103648431
如下:demo测试通过, 利用 response.getOutputStream() 、HttpServletResponse response 来设置响应头等信息。
java
@RequestMapping(value = "/xxx/getExcel", method = RequestMethod.GET)
public void getExcel(HttpServletResponse response) throws IOException {
//配置文件名
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
String datetime = sdf.format(new Date());
String fileName = URLEncoder.encode("下载excel", "UTF-8") + datetime;
//响应内容格式
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
List<UserVO> list = excelService.getUserVOData();
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(response.getOutputStream(), UserCheckData.class).sheet("下载excel").doWrite(list);
}
UserCheckData.class 是自定义的excel对应的java类;其中的
@ExcelProperty注解中的value就是表头的信息,index是在第几列,没有加注解的不会导出。
java
@HeadRowHeight(20) // 表头行高
@ColumnWidth(15) // 表头行宽
@Data
public class SiUserCheckData{
/**
* 用户名
*/
@ExcelProperty(value = "用户名", index = 0)
private String username;
/**
* 手机号
*/
@ExcelProperty(value = "手机号", index = 0)
private String mobile;
}
如上demo,经过测试,注意点如下:
- response 来设置响应头等信息,记得要放在EasyExcel.write 写流之前。
- controller方法写成void即可。
response的三个属性:编码、类型、头文件
流写出时,关键是配置response的三个属性:编码、类型、头文件
1、ContentType:传输文件类型
application/octet-stream------------------自动匹配文件类型
application/force-download--------------强制下载
text/pain---------------------------------------文本文件
application/vnd.ms-excel-----------------excel文件
2、CharacterEncoding:编码采用通用的UTF-8
3、Header:setHeader(name,value),有两个参数
示例:
java
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition","attachment;filename=problems"+AMDateUtil.date2String(new Date(),"yyyyMMdd")+".xlsx");
4. demo3:SpringBoot项目中集成EasyExcel实现Excel文件导入(同步处理数据)
SpringBoot项目中集成EasyExcel实现Excel文件上传至MySQL
参考URL: https://blog.csdn.net/riemann_/article/details/103639254
使用easyExcel导入大批量数据
参考URL: https://blog.csdn.net/qq_36109477/article/details/104909535
[推荐]springboot整合阿里easyexcel2.x实现海量数据excel导入导出demo
参考URL: https://www.cnblogs.com/zhengwj-joker/p/12808979.html
整体思路:
- 引入easyExcel maven。
- 定义导入导出exel字段对应的实体类。(使用easyExcel相关注解)
- 自定义 上传Excel的监听类 实现 AnalysisEventListener<你自己定义的excel模型类>。
核心就是这个监听器类,实现相关方法。
经过测试: 监听器这个类不能够被Spring管理,每次使用单独的new出来。
java
// 该类无法交给spring管理
public class ConfigFilterListener extends AnalysisEventListener<ConfigFilterImport> {
private static final Logger logger = LoggerFactory.getLogger(ConfigFilterListener.class);
private static final int BATCH_COUNT = 10000;
List<ConfigFilterImport> list = new ArrayList<>();
private ConfigFilterDao configFilterDao;
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*/
public ConfigFilterListener(ConfigFilterDao configFilterDao){
this.configFilterDao = configFilterDao;
}
/**
* 这个每一条数据解析都会来调用
*
* @param configFilter
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param analysisContext
*/
@Override
public void invoke(ConfigFilterImport configFilter, AnalysisContext analysisContext) {
list.add(configFilter);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
logger.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
logger.info("{}条数据,开始存储数据库!", list.size());
configFilterDao.save(list);
logger.info("存储数据库成功!");
}
}
参考原博主URL(https://www.cnblogs.com/zhengwj-joker/p/12808979.html
),即可。
4.1 AnalysisEventListener
上文中,自定义 上传Excel的监听类 实现 AnalysisEventListener<你自己定义的excel模型类>,
其中, invoke() 和 doAfterAllAnalysed() 是必须实现的方法。
在 invoke() 中,我们将数据封装到 list 中,再在控制器中,通过 getter() 方法获取数据,这样我们就可以获取到 easyexcel 帮我们解析好的数据,再将数据进行类型转化,这样,我们就可以对数据进行写入操作。
注意:
- 每解析一行会回调invoke()方法。
- 整个excel解析结束会执行doAfterAllAnalysed()方法
经过测试,自定义监听类 实现 AnalysisEventListener不能被spring管理。即使你加了 @Component注解,发现里面 @Autowired 注入不了spring 的bean!
那么,我们要使用spring bean应该怎么做呢?
思路:监听器对象 可以在创建的时候把dao当做参数传进去。
我们自定义监听器类的构造体传入,需要用到bean,如一些Dao
java
/**
*
* 不要使用自动装配
* 将dao当参数传进来
*/
public DemoDataListener(TeacherDao teacherDao) {
this.teacherDao = teacherDao;
}
java
/**
* 添加数据库用到的dao
*/
@Autowired
private TeacherDao teacherDao;
/**
* 最简单的读
*/
@Test
public void simpleRead() {
String fileName = "/Users/lubingyang/Desktop/hhhh.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
/**
* 参数1 要读取的文件
* 参数2 要读取的数据对应的实体类类对象
* 参数3 监听器对象 可以在创建的时候把dao当做参数传进去
*/
EasyExcel.read(fileName, Teacher.class, new DemoDataListener(teacherDao)).sheet().doRead();
}
三、工作常用参考
1. easyexcel 上传返回结果给前端(返回成功/失败数量及原因)
基于EasyExcel的读取exl并返回成功/失败数量及原因,并将导入失败exl的导出到系统路径中
参考URL: https://blog.csdn.net/qq_37361535/article/details/105687708
https://blog.csdn.net/weixin_42059737/article/details/103891013
参考URL: https://blog.csdn.net/weixin_42059737/article/details/103891013
整体思路:
自定义类bean,spring管理,专门处理统计哪些入库成功,哪些失败,在自定义excel监听器构造函数中传入。
controller层如何返回给界面,哪些成功或失败呢?
其中controller层需要返回给前端的数据,可以利用该思想。在监听器构造函数添加需要返回的实例。监听器里面做相关赋值,controller层直接返回即可。
controller层,demo如下:
java
@ResponseBody
@RequestMapping(value = "orderImport", method = RequestMethod.POST, produces = Constant.CONTENT_TYPE_UTF8)
public RestResponse orderImport(HttpServletRequest request, @RequestParam(value = "file") MultipartFile file) throws Exception {
UserVO userVo = this.getCurrentUser(request);
// 初始化ajax返回对象 默认是操作成功
RestResponse build = RestResponse.build();
EasyExcel.read(file.getInputStream(), new NoModleDataListener(orderService, userVo, build)).sheet().doRead();
// 直接返回 如果错误这个对象的值已被改变 如果没有错误值没有被改变 返回的是默认成功的对象
return build;
// return orderService.importOrder(userVo, file);
}
建议直接参考原文。
2. easyexcel 导入数据校验
easyExcel+validation+正则实现excel导入校验
参考URL: https://www.yuque.com/oushidazhutou/lwb5fl/mwymlq
四、参考
EasyExcel2.0 实现模板下载、导入和导出功能
参考URL: https://liuyanzhao.com/10060.html
EasyExcel操作API与示例
参考URL: https://www.it610.com/article/1296387796709220352.htm
EasyExcel读取文件-同步处理数据
参考URL: https://www.cnblogs.com/ngrzr/p/11982697.html
SpringBoot图文教程14---阿里开源EasyExcel「为百万数据读写设计」
参考URL: https://my.oschina.net/u/3555122/blog/4355952
惊了!如何通过阿里 EasyExcel 7 行代码, 优雅地实现 Excel 文件导出功能?
参考URL: https://blog.csdn.net/wutian842929/article/details/106994662/
easyExcel+validation+正则实现excel导入校验