前言

前阵时间好奇下载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函数主要通过流操作获取。

详细讲解Java使用EasyExcel函数来操作Excel表(附实战)-LMLPHP

对于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;
	}
}

最后截图如下:

详细讲解Java使用EasyExcel函数来操作Excel表(附实战)-LMLPHP

读取函数的功能:

在这之前需要加一个监听器:

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();
	}

}

截图如下:

详细讲解Java使用EasyExcel函数来操作Excel表(附实战)-LMLPHP

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("导入成功");
}
12-28 14:54