一、引入 easyexcel 依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>${easyexcel.version}</version> </dependency>二、核心代码
public String readExcel(MultipartFile file) throws IOException { // 创建 StringBuilder StringBuilder stringBuilder = new StringBuilder("原始的excel数据\n"); // 获取文件字节数组 byte[] fileBytes = file.getBytes(); // 创建 Excel 读取器 // ByteInputSream(byte[] buf) -> 从字节数组创建一个内存输入流 // EasyExcel.raed(InputStream inputStream) -> ExcelReaderBuilder 对象 // .build() -> 来自 ExcelReaderBuilder类,返回值为 ExcelReader 对象 ExcelReader excelReader = EasyExcel.read(new ByteArrayInputStream(fileBytes)).build(); // .excelExecutor() -> 来自于 ExcelReader 执行器对象,获取执行器对象,用于执行各种操作, 返回 ExcelExecutor 对象 // .sheetList() -> 来自于 ExcelExecutor 类,读取 Excel 文件中所有工作表的元数据,放回值为 List<ReadSheet> List<ReadSheet> readSheets = excelReader.excelExecutor().sheetList(); // 遍历每一个 sheet for(ReadSheet readSheet : readSheets) { // .getSheetNo() 方法 -> 来自 ReadSheet 类 // 获取当前工作表的序号(索引) int sheetNo = readSheet.getSheetNo(); // 创建行数据容器 List<List<String>> sheetRows = new ArrayList<>(); // new ByteArrayInputStream(fileBytes) -> 再次创建内存输出流, 指定要处理的数据 // Map<Integer, String> 指定每行数据的类型,这次用 Map, 键是列索引(Integer), 值是单元格内容(String) // new ReadListener<Map<Integer, String>>() {...} -> 匿名内部类写法, ReadListener是 EasyExcel 的读取监听器接口, 定义如何处理每一行数据(通过 ReadListener 监听器) EasyExcel.read(new ByteArrayInputStream(fileBytes), new ReadListener<Map<Integer, String>>() { // 重写 invoke 方法 // invoke 方法来自 ReadListener 接口 -> 每读取一行数据就会自动回调此方法 // 参数1data: 当前行的数据, Map<Integer, String> 类型 // 参数2analysisContext: 分析上下文 @Override public void invoke(Map<Integer, String> data, AnalysisContext context) { // 创建当前行的列数据容器 List<String> rowData = new ArrayList<>(); // 这行代码的作用是找出当前行最大的列列索引,如果没有任何列(空行)则返回-1 // data.KeySet() -> 来自 Map 接口,获取 Map 中所有键的集合, 返回值 Set<Integer>,所有列索引的集合 // .stream() -> 来自 Collection 接口,将集合转换为 Stream 流,用于函数式操作,返回值为 Stream<Integer> 流对象 // .mapToInt(Integer::intValue) -> 来自 Stream 接口,将 Stream 中的所有元素映射为 int 基本类型, 返回值为 IntStream 整数流 // .max() -> 来自 IntStream 接口,获取流中的最大值, 返回值为 OptionalInt, 可能包含最大值,也可能为空(如果流为空) // .orElse(-1) -> 来时 OptionalInt 类, 如果 OptionalInt 有值则返回该值, 否则返回默认值 int maxColumnIndex = data.keySet().stream().mapToInt(Integer::intValue).max().orElse(-1); for(int i = 0; i <= maxColumnIndex; i++) { // value 为单元格值或空字符串 String value = data.getOrDefault(i, ""); // trim() -> 来自 String 类,去除字符串首尾的空白字符 rowData.add(value.trim()); } sheetRows.add(rowData); } // 重写 doAfterAllAnalysed 方法 // doAfterAllAnalysed 方法,来自 ReadListener 接口, 将所有行读取完毕后自动回调次方法 // 参数 AnalysisContext 分析上下文 @Override public void doAfterAllAnalysed(AnalysisContext context) { } // .sheet(sheetNo) -> 来自 ExcelReaderBuilder 类,指定要读取的 sheet(按序号),返回值为 ExcelReaderBuilder自身 // .headRowNumber(0) -> 来自 ExcelReaderBuilder 类,设置表头函数, 参数0表示不跳过任何行,从第一行开始读取,ExcelReaderBuilder(自身) // .doRead() -> 来自 ExcelReaderBUilder 类,真正开始执行读取操作, 会触发 invoke 方法逐行回调 }).sheet(sheetNo).headRowNumber(0).doRead(); // 拼接 Sheet 标题 stringBuilder.append("\n==sheet: ").append(readSheet.getSheetName()) .append("(第").append(sheetNo + 1).append("个工作表)==\n"); for(List<String> row : sheetRows) { for(int i = 0; i < row.size(); i++) { if(i > 0) { stringBuilder.append("|"); } stringBuilder.append(row.get(i)); } stringBuilder.append("\n"); } } return stringBuilder.toString(); }三、测试
package com.linzhixin.test; import com.linzhixin.service.ChatService; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.nio.file.Files; public class ChatServiceTest { private ChatService chatService = new ChatService(); @Test public void testReadExcel() throws IOException { String path = "D:\\浏览器下载\\chat2excel-master\\excel数据\\国家GDP.xlsx"; // 创建 File 对象 File excelFile = new File(path); // 读取文件为字节数组 byte[] excelBytes = Files.readAllBytes(excelFile.toPath()); // 创建 MultipartFile 对象 // MockMultipartFile -> Spring 测试工具类,用于模拟文件上传对象 // 第一个参数:excelFile.getName -> 文件名参数表 // 第二个参数:excelFile.getName -> 原始文件名 // 第三个参数:application/vnd.openxmlformats-officedocument.spreadshhettml.sheet" -> 文件 MIME 类型 // 第四个参数:excelBytes -> 文件字节内容 MultipartFile file = new MockMultipartFile( excelFile.getName(), excelFile.getName(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", excelBytes ); //执行并打印结果 System.out.println(chatService.readExcel(file)); } }五、参考文档链接
读Excel | Easy Excel 官网