大型项目技术栈第六讲 EasyExcel的使用
时间:2022-07-25
本文章向大家介绍大型项目技术栈第六讲 EasyExcel的使用,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
EasyExcel的使用
一、EasyExcel
1.EasyExcel简介
- easyExcel是阿里巴巴开源poi插件之一,当前最新版本2.1.3,poi版本3.17
- 主要解决了poi框架使用复杂,sax解析模式不容易操作,数据量大起来容易OOM,解决了POI并发造成的报错
2.EasyExcel优势
- 注解式自定义操作。
- 输入输出简单,提供输入输出过程的接口
- 支持一定程度的单元格合并等灵活化操作
3.EasyExcel开发示例
3.1 导入依赖包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.3</version>
</dependency>
3.2 创建实体类
实体类对需要导出或者导入的字段增加@ExcelProperty注解,index值为对应excel中的列,value为表头,format为日期格式化
public class PersonDto{
/** id */
@ExcelProperty(index = 0 , value = "id")
private String id;
/** 姓名 **/
@ExcelProperty(index = 1 , value = "姓名")
private String name;
/** 生日 **/
@ExcelProperty(index = 2 , value = "生日" , format = "yyyy-MM-dd")
//新版本提供了一个@com.alibaba.excel.annotation.format.DateTimeFormatDateTimeFormat替代format属性
private String birth;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirth() {
return birth;
}
public void setBirth(String birth) {
this.birth = birth;
}
}
3.3 写excel
测试类:
public class TestExcel {
private List<PersonDto> createModelList() {
List<PersonDto> PersonDtos = new ArrayList<>();
for (int i = 0; i < 100; i++) {
PersonDto personDto = new PersonDto();
personDto.setName("学Java"+i);
personDto.setId(""+i);
personDto.setBirth(new Date().toString());
PersonDtos.add(personDto);
}
return PersonDtos;
}
/**
* 最简单的写
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 直接写即可
*/
@Test
public void simpleWrite() {
// 写法1
String fileName = "D:\person.xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, PersonDto.class).sheet("模板").doWrite(createModelList());
// 写法2
fileName = "D:\person.xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, PersonDto.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
excelWriter.write(createModelList(), writeSheet);
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
}
3.4读excel
AnalysisEventListener<PersonDto>:
读取excel必须提供一个监听类继承该抽象类
public void invoke(PersonDto data, AnalysisContext context)
在读取excel的每一行,都会去调用该监听器的invoke方法,自动传入解析好的java对象
public void doAfterAllAnalysed(AnalysisContext context)
在读取excel结束的时候,会调用该方法
3.4.1 PersonDtoListener
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public class PersonDtoListener extends AnalysisEventListener<PersonDto> {
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<PersonDto> list = new ArrayList<PersonDto>();
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private PersonDao personDao;
public PersonDtoListener() {
}
/**
* 官方问题提到不能用spring管理该监听器对象,所以不能直接用依赖注入注解注入
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param personDAO
*/
public PersonDtoListener(PersonDao personDAO) {
this.personDao = personDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
public void invoke(PersonDto data, AnalysisContext context) {
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
}
/**
* 加上存储数据库
*/
private void saveData() {
System.out.println(list);
personDao.save(list);
}
}
3.4.2 测试类
/**
* 最简单的读
* <p>1. 创建excel对应的实体对象 参照{@link cn.nyse.entity.PersonDto}
* <p>2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link cn.nyse.entity.PersonDtoListener}
* <p>3. 直接读即可
*/
@Test
public void simpleRead() {
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
// 写法1:
String fileName = "F:\dfbz\课件2.0\guguanjia2.0\some.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, PersonDto.class, new PersonDtoListener()).sheet().doRead();
// 写法2:
fileName = "F:\dfbz\课件2.0\guguanjia2.0\some.xlsx";
ExcelReader excelReader = EasyExcel.read(fileName, PersonDto.class, new PersonDtoListener()).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
}
二、vue的文件上传
1.步骤
a.在input组件中添加点击事件@change=“upload”
b.在事件处理函数中传入事件对象,通过事件对象获取文件对象e.target.files[0]
c.创建表单对象let formData = new FormData();
d.放入文件对象 formData.append(“file”,e.target.files[0]);
d.通过axios设置请求头headers:{‘content-type’:‘multipart/form-data’}和提交方式post
e.后台通过上传对象MultipartFile file接受
页面:
<div id="div1">
<input type="file" accept=".xls,.xsls" @change="upload"/>
</div>
<script>
var vm = new Vue({
el:'#app',
/*
由于vue的响应式原理 data 如果是一个对象,对象中使用this不会自动绑定为vue对象,需要通过回调函数方式,vue才会在调用该函数的时候,进行双向绑定,并且自动传入
当前vue对象到函数中
*/
data:function(){
console.log(this);
return {
file:''
}
},
methods:{
upload:function(e){
this.file = e.target.files[0];
console.log(this.file);
let formData = new FormData();
formData.append("file",this.file);
axios({
method:'post',
headers:{'content-type':'multipart/form-data'},
url:'/guguanjia/manager/area/importExcel',
data:formData
}).then(response =>{
console.log(response.data);
}).catche(function(error){
});
}
}
});
</script>
后台
@RequestMapping("importExcel")
public void importExcel(@RequestParam("file")MultipartFile file){
System.out.println((file.getOriginalFilename()));
。。。
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Day34:第一个只出现一次的字符
- 第四天:文本处理流程——分词
- 腾讯云 云开发 部署 Blazor网站
- 简单的 CAS 实现 SSO 单点登录
- 为什么 Java 中“1000==1000”为false,而”100==100“为true?
- 详解股票买卖算法的最优解(一)
- 详解股票买卖算法的最优解(二)
- Bertopology: Bert及其改进型总结
- Go 如何实现热重启
- Serverless ETL —— 蘑菇街实战落地
- Day35:数组中的逆序对
- Day36:两个链表的第一个公共结点
- 第5天: 文本处理流程——拼写纠错
- Spring 自定义类型转换器
- Spring BeanPostProcessor 的执行顺序