赞
踩
https://github.com/alibaba/easyexcel
快速开始:https://www.yuque.com/easyexcel/doc/easyexcel
使用场景
在日常开发中 我们难免需要导入数据 可以用EasyExcel来解决
创建一个普通maven项目 加入依赖
<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dddPqkTA-1652199426737)(C:/Users/jiejie/AppData/Roaming/Typora/typora-user-images/image-20220510234119590.png)]
我们需要创建好与excel列名相对应的实体类
@ExcelProperty 表示excel列名
package com.atguigu.easyexcel.dto;
@Data
public class ExcelStudentDTO {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("生日")
private Date birthday;
@ExcelProperty("薪资")
private Double salary;
}
public class ExcelWriteTest { @Test public void simpleWriteXlsx() { String fileName = "d:/excel/simpleWrite.xlsx"; //需要提前新建目录 // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, ExcelStudentDTO.class).sheet("模板").doWrite(data()); } //辅助方法 private List<ExcelStudentDTO> data(){ List<ExcelStudentDTO> list = new ArrayList<>(); //算上标题,做多可写65536行 //超出:java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535) for (int i = 0; i < 65535; i++) { ExcelStudentDTO data = new ExcelStudentDTO(); data.setName("Helen" + i); data.setBirthday(new Date()); data.setSalary(123456.1234); list.add(data); } return list; } }
结果就是上面那张图片哈 不粘了
@Test
public void simpleWriteXls() {
String fileName = "d:/excel/simpleWrite.xls";
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, ExcelStudentDTO.class).excelType(ExcelTypeEnum.XLS).sheet("模板").doWrite(data());
}
参考文档https://www.yuque.com/easyexcel/doc/read
简单描述一下 读的操作 需要实现一个监听器 实现监听器的方法
@Slf4j public class ExcelStudentDTOListener extends AnalysisEventListener<ExcelStudentDTO> { /** * 这个每一条数据解析都会来调用 */ @Override public void invoke(ExcelStudentDTO data, AnalysisContext context) { log.info("解析到一条数据:{}", data); } /** * 所有数据解析完成了 都会来调用 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { log.info("所有数据解析完成!"); } }
测试方法
public class ExcelReadTest { /** * 最简单的读 */ @Test public void simpleReadXlsx() { String fileName = "d:/excel/simpleWrite.xlsx"; // 这里默认读取第一个sheet EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).sheet().doRead(); } @Test public void simpleReadXls() { String fileName = "d:/excel/simpleWrite.xls"; EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).excelType(ExcelTypeEnum.XLS).sheet().doRead(); } }
在真实的项目中 我们读取到 数据之后 肯定要持久化到数据库中 这个操作就由我们的监听器来完成
接口:DictMapper
void insertBatch(List<ExcelDictDTO> list);
xml:DictMapper.xml
<insert id="insertBatch"> insert into dict ( id , parent_id , name , value , dict_code ) values <foreach collection="list" item="item" index="index" separator=","> ( #{item.id} , #{item.parentId} , #{item.name} , #{item.value} , #{item.dictCode} ) </foreach> </insert>
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.atguigu.srb.mapper.DictMapper; import com.atguigu.srb.pojo.dto.ExcelDictDTO; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; /** * 监听 * 再读取数据的同时 对数据进行插入操作 * @author : look-word * @date : 2022-05-10 21:35 **/ @Slf4j //@AllArgsConstructor //全参 @NoArgsConstructor //无参 public class ExcelDictDTOListener extends AnalysisEventListener<ExcelDictDTO> { /** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 100; /** * 缓存的数据 */ private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); /** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */ private DemoDAO demoDAO; public DemoDataListener() { // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数 demoDAO = new DemoDAO(); } /** * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 * * @param demoDAO */ public DemoDataListener(DemoDAO demoDAO) { this.demoDAO = demoDAO; } /** * 这个每一条数据解析都会来调用 * * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */ @Override public void invoke(DemoData data, AnalysisContext context) { log.info("解析到一条数据:{}", JSON.toJSONString(data)); cachedDataList.add(data); // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM if (cachedDataList.size() >= BATCH_COUNT) { saveData(); // 存储完成清理 list cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } } /** * 所有数据解析完成了 都会来调用 * * @param context */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 这里也要保存数据,确保最后遗留的数据也存储到数据库 saveData(); log.info("所有数据解析完成!"); } /** * 加上存储数据库 */ private void saveData() { log.info("{}条数据,开始存储数据库!", cachedDataList.size()); demoDAO.save(cachedDataList); log.info("存储数据库成功!"); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。