前言
前阵时间好奇下载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> {
@Override
public void invoke(ExcelData data, AnalysisContext context) {
// 处理每一行数据的逻辑
System.out.println("Read data: " + data);
}
@Override
public 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 {
@Override
public void sheet(int sheetNo, Sheet sheet) {
// 对每个 sheet 进行处理的逻辑
}
@Override
public void row(int rowNum, Row row) {
// 对每一行进行处理的逻辑
}
@Override
public 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> {
@Override
public void invoke(ExcelData data, AnalysisContext context) {
// 数据处理逻辑,可以将数据存储到数据库或进行其他操作
System.out.println("Read data: " + data);
}
@Override
public 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
*/
@Override
public void invoke(Info info, AnalysisContext analysisContext) {
list.add(info);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() > BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param analysisContext
*/
@Override
public 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("导入成功");
}