目录
- 前言
- 1. EasyExcel类
- 2. 原理分析
- 3. demo
- 4. 实战
前言
前阵时间好奇下载Excel,特意学习实战了该功能:详细讲解Java使用HSSFWorkbook函数导出Excel表(附实战)
现在发觉还有个EasyExcel也可专门用来读写Excel表
1. EasyExcel类
添加相应的依赖包
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.5</version>
</dependency>
EasyExcel 是一个基于 Java 的开源工具,用于简化 Excel 文件的读写操作。
具有易用性、高性能、低内存消耗的特点。
以下是 EasyExcel 的一些主要函数和用法:(本身有读和写的两种操作)
2. 原理分析
本身该函数通过继承EasyExcelFactory函数,主要在EasyExcelFactory函数中实现。
一、对于read函数主要通过流操作获取。
对于EasyExcel.read 方法中常用的一个read函数如下:
EasyExcel.read(fileName, head, readListener).sheet().doRead();
大致三个参数如下:
fileName
:Excel 文件的路径或输入流。head
:Excel 表头对应的实体类,定义了 Excel 表的结构。readListener
:数据读取的监听器,定义了数据读取的逻辑。
二、 Excel 表头的实体类:
在读取 Excel 文件时,需要定义一个实体类来映射 Excel 表头,每个字段对应一个表头列。这个实体类用于指定数据在 Java 对象中的存储结构。
public class ExcelData {private String name;private Integer age;// 其他字段...// 省略 getter 和 setter 方法
}
三、数据读取监听器:
EasyExcel 提供了 AnalysisEventListener
类来处理 Excel 数据的读取。
需要继承该类,并实现 invoke
方法来处理每一行数据的读取逻辑,以及doAfterAllAnalysed
方法来处理所有数据解析完成后的逻辑。
public class ExcelDataListener extends AnalysisEventListener<ExcelData> {@Overridepublic void invoke(ExcelData data, AnalysisContext context) {// 处理每一行数据的逻辑System.out.println("Read data: " + data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 所有数据解析完成后的逻辑}
}
四、Excel 写入:
EasyExcel 也提供了写入 Excel 文件的功能。
可以使用 EasyExcel.write
方法来配置写入参数,然后调用 sheet
方法指定写入的 sheet,最后调用 doWrite
方法执行写入操作。
EasyExcel.write(fileName, head).sheet("Sheet1").doWrite(dataList);
大致的参数如下:
- fileName:写入的 Excel 文件路径。
- head:Excel 表头对应的实体类。
- dataList:要写入的数据列表。dataList 应该是一个 List,其中的元素是实体类的对象
五、Excel 写入监听器:
写入 Excel 文件时进行一些额外的处理,可以使用写入监听器 WriteHandler
。
public class ExcelWriteHandler implements WriteHandler {@Overridepublic void sheet(int sheetNo, Sheet sheet) {// 对每个 sheet 进行处理的逻辑}@Overridepublic void row(int rowNum, Row row) {// 对每一行进行处理的逻辑}@Overridepublic void cell(int cellNum, Cell cell) {// 对每个单元格进行处理的逻辑}
}
在写入 Excel 文件时,通过 excelWriter.registerWriteHandler(new ExcelWriteHandler())
注册写入监听器即可。
3. demo
假设创建的实体类如下:
import lombok.Data;@Data
@NoArgsConstructor
public class ExcelData {private String name;private Integer age;private String occupation;// 其他字段...// 省略 getter 和 setter 方法public ExcelData(String name, Integer age, String occupation) {this.name = name;this.age = age;this.occupation = occupation;}
}
写入Excel的函数:
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;import java.util.ArrayList;
import java.util.List;public class test1 {public static void main(String[] args) {String fileName = "d:\\xxx\\测试.xlsx"; // 替换成实际的文件路径// 准备要写入的数据List<ExcelData> dataList = initData();// // 写入 Excel 文件
// ExcelWriter excelWriter = EasyExcel.write(fileName, ExcelData.class).build();
// // 创建写入的 sheet
// WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();
// // 写入数据
// excelWriter.write(dataList, writeSheet);//与上面同理EasyExcel.write(fileName, ExcelData.class).sheet("模板").doWrite(dataList);System.out.println("Excel 写入完成!");}// 初始化要写入的数据private static List<ExcelData> initData() {List<ExcelData> dataList = new ArrayList<>();dataList.add(new ExcelData("John", 25, "Engineer"));dataList.add(new ExcelData("Alice", 30, "Manager"));dataList.add(new ExcelData("Bob", 28, "Developer"));// 添加更多数据...return dataList;}
}
最后截图如下:
读取函数的功能:
在这之前需要加一个监听器:
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;import java.util.Map;public class ExcelListen extends AnalysisEventListener<ExcelData> {@Overridepublic void invoke(ExcelData data, AnalysisContext context) {// 数据处理逻辑,可以将数据存储到数据库或进行其他操作System.out.println("Read data: " + data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 所有数据解析完成后的操作}
}
其读写的函数如下:
import com.alibaba.excel.EasyExcel;public class test1 {public static void main(String[] args) {String fileName = "d:\\xx\\测试.xlsx"; // 替换成实际的文件路径// 使用 EasyExcel 读取 Excel 文件EasyExcel.read(fileName, ExcelData.class, new ExcelListen()).sheet().doRead();}}
截图如下:
4. 实战
对于实战中,多数是结合springboot以及数据库中,主要将其Excel中导入到界面中,同时也保存在数据库中!
关联数据库Entity的类如下:
@Data
@TableName("xx")
@ApiModel(value = "Info对象", description = "Info对象")
public class Info{@ApiModelProperty(value = "设备编号")@ExcelProperty("设备编号")private String equipmentNo;
}
对应的监听类函数如下:(对于监听类的函数实际看个人数据库补充即可!以下只是给个模板)
public class InfoDataListener extends AnalysisEventListener<Info> {/*** 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 5;List<Info> list = new ArrayList<Info>();private IInfoService infoService;private IInfoRunningDataService infoRunningDataService;//其他public InfoDataListener(IInfoService infoService) {this.infoService = infoService;}//弄构造函数public InfoDataListener(IInfoService infoService,//其他) {this.infoService = infoService;//其他}/*** 这个每一条数据解析都会来调用** @param info one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param analysisContext*/@Overridepublic void invoke(Info info, AnalysisContext analysisContext) {list.add(info);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() > BATCH_COUNT) {saveData();// 存储完成清理 listlist.clear();}}/*** 所有数据解析完成了 都会来调用** @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();}/*** 除了保持自己本身,还要保存运行数据表,* xxx*/public void saveData() {infoService.saveBatch(list);ArrayList<InfoRunningData> infoRunningDatas = new ArrayList<InfoRunningData>();// 其他数据一块list.stream().forEach(info ->{InfoRunningData infoRunningData = new InfoRunningData();infoRunningData.setInfoId(info.getId());infoRunningDatas.add(infoRunningData);//其他数据一并处理});infoRunningDataService.saveBatch(infoRunningDatas);//其他数据一并处理}
}
controller函数:
@PostMapping("/importExcel")
@ResponseBody
public R upload(MultipartFile file) throws IOException {EasyExcel.read(file.getInputStream(), Info.class, new InfoDataListener(infoService,infoxxService,infoyyService )).sheet().doRead();
// EasyExcel.read(file.getInputStream(),Info.class,new InfoDataListener(infoService)).sheet().doRead();return R.success("导入成功");
}