当前位置:   article > 正文

详细讲解Java使用EasyExcel函数来操作Excel表(附实战)_java easyexcel解析excel

java easyexcel解析excel

前言

前阵时间好奇下载Excel,特意学习实战了该功能:详细讲解Java使用HSSFWorkbook函数导出Excel表(附实战)
现在发觉还有个EasyExcel也可专门用来读写Excel表

1. EasyExcel类

添加相应的依赖包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.5</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

EasyExcel 是一个基于 Java 的开源工具,用于简化 Excel 文件的读写操作。

具有易用性、高性能、低内存消耗的特点。

以下是 EasyExcel 的一些主要函数和用法:(本身有读和写的两种操作)

2. 原理分析

本身该函数通过继承EasyExcelFactory函数,主要在EasyExcelFactory函数中实现。

一、对于read函数主要通过流操作获取。

在这里插入图片描述

对于EasyExcel.read 方法中常用的一个read函数如下:

EasyExcel.read(fileName, head, readListener).sheet().doRead();
  • 1

大致三个参数如下:

  • fileName:Excel 文件的路径或输入流。
  • head:Excel 表头对应的实体类,定义了 Excel 表的结构。
  • readListener:数据读取的监听器,定义了数据读取的逻辑。

二、 Excel 表头的实体类:

在读取 Excel 文件时,需要定义一个实体类来映射 Excel 表头,每个字段对应一个表头列。这个实体类用于指定数据在 Java 对象中的存储结构。

public class ExcelData {
    private String name;
    private Integer age;
    // 其他字段...

    // 省略 getter 和 setter 方法
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三、数据读取监听器:

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) {
        // 所有数据解析完成后的逻辑
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

四、Excel 写入:

EasyExcel 也提供了写入 Excel 文件的功能。

可以使用 EasyExcel.write 方法来配置写入参数,然后调用 sheet 方法指定写入的 sheet,最后调用 doWrite 方法执行写入操作。

EasyExcel.write(fileName, head).sheet("Sheet1").doWrite(dataList);
  • 1

大致的参数如下:

  • 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) {
        // 对每个单元格进行处理的逻辑
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在写入 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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

写入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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

最后截图如下:

在这里插入图片描述

读取函数的功能:

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

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) {
		// 所有数据解析完成后的操作
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

其读写的函数如下:

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

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

截图如下:

在这里插入图片描述

4. 实战1

对于实战中,多数是结合springboot以及数据库中,主要将其Excel中导入到界面中,同时也保存在数据库中!

关联数据库Entity的类如下:

@Data
@TableName("xx")
@ApiModel(value = "Info对象", description = "Info对象")
public class Info{

	@ApiModelProperty(value = "设备编号")
	@ExcelProperty("设备编号")
	private String equipmentNo;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

对应的监听类函数如下:(对于监听类的函数实际看个人数据库补充即可!以下只是给个模板)

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);
		//其他数据一并处理
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

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("导入成功");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4. 实战2

与上面的原理类似

以下需求是做一个月计划的导入数据!

entity类:(excel中各个栏目数据也只会识别这些)

@Data
public class MonthPlanExcel implements Serializable {
	private static final long serialVersionUID = 1L;

	private Long parentId;
	/**
	 * 设备机种
	 */
	@ApiModelProperty(value = "设备机种")
	private String model;
	/**
	 * 设备编号
	 */
	@ApiModelProperty(value = "设备编号")
	@ExcelProperty("设备号")
	private String equipmentNo;
	/**
	 * 工单类别
	 */
	@ApiModelProperty(value = "工单类别")
	@ExcelProperty("类型")
	private String orderClass;
	/**
	 * 工单类型
	 */
	@ApiModelProperty(value = "工单类型")
	@ExcelProperty("计划内容")
	private String orderType;
	/**
	 * 工单编号
	 */
	@ApiModelProperty(value = "工单编号")
	private String orderNo;
	/**
	 * 备注
	 */
	@ApiModelProperty(value = "备注")
	@ExcelProperty("备注")
	private String remark;
	/**
	 * 完成时间
	 */
	@ApiModelProperty(value = "完成时间")
	@ExcelProperty(value = "完成时间",converter = LocalDateTimeConverter.class)
	private Date finishTime;

	@ApiModelProperty(value = "负责人")
	@ExcelProperty("负责人")
	private String head;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

对应的监听类:

@AllArgsConstructor
public class MonthPlanExcelListener implements ExcelImporter<MonthPlanExcel> {
	
	// 来源于:public interface IInfoService extends BaseService<Info> {
	private final  IInfoService iInfoService;

	private final  Long parentId;

	private final String parentModel;

	@Override
	// 主要写一个整体的逻辑,具体工程的逻辑看个人
	public void save(List<MonthPlanExcel> data) {
		List<MonthPlanDetail> list = new ArrayList<>();
		for(MonthPlanExcel excel : data){
			Info info = iInfoService.getOneByNUmber(excel.getEquipmentNo());
			// 通过controller传输的数据进行判定
			if( parentModel == null || (parentModel.equals(info.getModel())) ){
				MonthPlanDetail entity = new MonthPlanDetail();
				entity.setModel(info.getModel());
				entity.setParentId(parentId);
				entity.setEquipmentNo(excel.getEquipmentNo());
				entity.setHead(excel.getHead());
				entity.setOrderClass(excel.getOrderClass());
				entity.setOrderType(excel.getOrderType());
				entity.setFinishTime(excel.getFinishTime());
				entity.setRemark(excel.getRemark());

				list.add(entity);
			}
		}

		iMonthPlanDetailService.saveBatch(list);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

对应的controller类如下:

	@PostMapping("/import")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "文件数据导入", notes = "传入excel")
	public R importExcel(MultipartFile file,Long parentId, String parentModel) {
		MonthPlanExcelListener monthPlanExcelListener = new MonthPlanExcelListener(monthPlanDetailService,iInfoService,parentId,parentModel);
		ExcelUtil.save(file,monthPlanExcelListener, MonthPlanExcel.class);
		return R.success("操作成功");
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/pgrmghi/article/detail/61115
推荐阅读
相关标签
  

闽ICP备14008679号