EasyExcel

pom.xml

java 复制代码
        <!-- 引入EasyExcel依赖,用于处理Excel读写操作 -->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>easyexcel</artifactId>
             <version>3.1.1</version>
         </dependency>
         <!-- 引入FastJSON依赖,用于处理JSON格式数据的序列化和反序列化 -->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
             <version>2.0.21</version>
         </dependency>

准备一个Excel文件

复制代码
 字符串标题   日期标题          数字标题
 字符串0    2024/5/29 21:16     0.56
 字符串1    2024/5/30 21:16     1.56
 字符串2    2024/5/31 21:16     2.56
 字符串3    2024/6/1 21:16      3.56
 字符串4    2024/6/2 21:16      4.56
 字符串5    2024/6/3 21:16      5.56
 字符串6    2024/6/4 21:16      6.56
 字符串7    2024/6/5 21:16      7.56
 字符串8    2024/6/6 21:16      8.56

实体类

java 复制代码
 @Data
 @HeadRowHeight(20)
 @ColumnWidth(20)
 public class DemoData {
     @ExcelProperty("字符串标题")
     private String string;
     @ExcelProperty("日期标题")
     private Date date;
     @ExcelProperty("数字标题")
     private Double doubleData;
     @ExcelIgnore
     private String ignore;
 }

读文件

读文件的两种方法

JavaExcelApplicationTests

java 复制代码
 /**
      * 读取Excel文件并将其内容转换为JSON格式的日志信息。
      * 该方法不接受参数且无返回值。
      * 主要步骤包括定位并读取Excel文件,将读取到的数据转换为DemoData对象的列表,
      * 然后将每个DemoData对象转换为JSON字符串,最后通过日志记录这些JSON字符串。
      *
      * {"date":"2024-05-29 21:16:57","doubleData":0.56,"string":"字符串0"}
      * {"date":"2024-05-30 21:16:57","doubleData":1.56,"string":"字符串1"}
      *
      */
     @Test
     void readExcel() {
         // 读取指定路径的Excel文件,指定表头类型为DemoData,读取所有sheet,同步读取数据
         List<DemoData> list = EasyExcel.read("D:\\Users\\黑池\\Desktop\\test.xlsx").head(DemoData.class).sheet().doReadSync();
 ​
         // 遍历读取到的数据列表,将每个DemoData对象转换为JSON字符串,并通过日志输出
         list.forEach(data ->{
             String string = JSON.toJSONString(data);
             log.info(string);
         });
     }
 ​
     /**
      * 读取Excel文件内容并打印
      *
      * 该方法没有参数。
      * 该方法没有返回值,但会读取指定路径的Excel文件,将每一行的内容转换为Map形式,并打印这些Map对象的信息。
      *
      *  {0=字符串0, 1=2024-5-29 21:16, 2=0.56}
      *  {0=字符串1, 1=2024-5-30 21:16, 2=1.56}
      */
     @Test
     void readExcel2() {
         // 读取Excel文件内容,同步执行
         List<Map<Integer,Object>> list = EasyExcel.read("D:\\Users\\黑池\\Desktop\\test.xlsx").sheet().doReadSync();
         // 遍历并打印读取到的每一行数据
         list.forEach(data ->{
             log.info(data.toString());
         });
     }

使用监听器读文件

java 复制代码
 import com.alibaba.excel.context.AnalysisContext;
 import com.alibaba.excel.event.AnalysisEventListener;
 import com.alibaba.excel.util.ListUtils;
 import com.alibaba.fastjson2.JSON;
 import com.baize.entity.DemoData;
 import com.baize.service.DemoService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 ​
 import java.util.List;
 ​
 @RequiredArgsConstructor
 @Slf4j
 public class DemoDataListener extends AnalysisEventListener<DemoData> {
 ​
 ​
     // 每次处理的数据批量大小
     private static final int BATCH_COUNT = 100;
 ​
     // 用于存储DemoData对象的列表,预先分配大小以提高性能
     private List<DemoData> list = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
 ​
     // DemoService的实例,用于执行与DemoData相关的业务逻辑
     private  final DemoService demoService;
 ​
 //      @RequiredArgsConstructor
 //    public DemoDataListener(DemoService demoService) {
 //        this.demoService = demoService;
 //    }
 ​
 //    @Override
 //    public void doAfterALlAnalysed(AnalysisContext context){
 //        //这里也要保存数据,确保最后遗留的数据也存储到数据库
 //        saveData();
 //        log.info("所有数据解析完成!");
 //    }
 ​
     /**
      * 保存数据到数据库。
      * 该方法不接受参数并且没有返回值。
      * 主要逻辑包括:
      * 1. 打印日志,记录待存储数据的数量。
      * 2. 调用demoService的saveData方法,将数据列表存储到数据库。
      * 3. 打印日志,表示数据存储成功。
      */
     private void saveData(){
         // 记录开始存储数据时的数据量
         log.info("{}条数据,开始存储数据库!",list.size());
         demoService.saveData(list); // 将数据列表保存到数据库
         // 记录数据保存成功
         log.info("存储数据库成功!");
     }
 ​
 ​
 /**
  * 被调用以处理DemoData数据,并将其存储到数据库中。
  * 当积累到一定数量的数据时,会批量存储到数据库中,以减少内存占用。
  *
  * @param demoData 待处理的数据对象,包含需要分析的数据。
  * @param analysisContext 分析上下文,提供额外的环境信息或配置。
  */
 @Override
 public void invoke(DemoData demoData, AnalysisContext analysisContext) {
     log.info("解析到一条数据:{}", JSON.toJSON(demoData));
     list.add(demoData);
 ​
     // 检查数据积累是否达到批量存储的阈值
     if (list.size() >= BATCH_COUNT) {
         saveData(); // 执行数据库存储操作
         // 存储完成后清理内存,准备接收新的数据批次
         list =  ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
     }
 }
 ​
 ​
     @Override
     public void doAfterAllAnalysed(AnalysisContext analysisContext) {
         //这里也要保存数据,确保最后遗留的数据也存储到数据库
         saveData();
         log.info("所有数据解析完成!");
     }
 }

service文件

java 复制代码
 public interface DemoService {
     void saveData(List<DemoData> list);
 }

serviceimpl文件

java 复制代码
 @Slf4j
 @Service
 public class DemoServiceimpl implements DemoService {
 ​
     public void saveData(){
         log.info("保存Excel数据到数据库中");
     }
     
     @Override
     public void saveData(List<DemoData> list) {
         log.info("正在保存Excel数据到数据库中");
     }
 }

JavaExcelApplicationTests

java 复制代码
     /**
      * 读取Excel文件的示例方法。
      * <p>
      * 此方法使用EasyExcel框架读取指定路径下的Excel文件("D:\\Users\\黑池\\Desktop\\test.xlsx"),
      * 并将数据映射到DemoData类中,然后通过DemoDataListener将数据进一步处理(这里依赖于demoService)。
      * <p>
      * 方法不接受任何参数,并且没有返回值。
      *
      * 解析到一条数据:{"date":"2024-05-29 21:16:57","doubleData":0.56,"string":"字符串0"}
      * 解析到一条数据:{"date":"2024-05-30 21:16:57","doubleData":1.56,"string":"字符串1"}
      * ......
      * 解析到一条数据:{"date":"2024-06-06 21:16:57","doubleData":8.56,"string":"字符串8"}
      * 9条数据,开始存储数据库!
      * 存储数据库成功!
      * 所有数据解析完成!
      */
     @Test
     void readExcel3() {
 ​
         // 使用EasyExcel框架读取Excel文件并处理数据
         EasyExcel.read("D:\\Users\\黑池\\Desktop\\test.xlsx", DemoData.class, new DemoDataListener(demoService)).sheet().doReadSync();
 ​
     }

写入文件

excel的写入

java 复制代码
     //模拟20条数据
     private List<DemoData> data() {
         List<DemoData> list = new ArrayList<DemoData>();
         for (int i = 0; i < 10; i++) {
             DemoData data = new DemoData();
             data.setString("字符串" + i);
             data.setDate(new Date());
             data.setDoubleData(0.56);
             list.add(data);
         }
         return list;
     }
 ​
     /**
      * 使用EasyExcel框架写入Excel文件的示例方法1。
      * 这个方法展示了两种不同的方式来写入Excel文件,均不需要手动关闭文件流。
      * 方法会根据调用方式的不同,演示了两种写入数据的方式。
      *
      * @since 3.0.0-beta1
      */
     @Test
     void writeExcel1(){
         // 写法1 JDK8+
         // 通过lambda表达式动态提供数据
         String fileName = "EasyExcelDemo" + System.currentTimeMillis() + ".xlsx";
         // 使用指定的类模型写入数据到第一个sheet,sheet名称为"模板"
         EasyExcel.write(fileName, DemoData.class)
                 .sheet("模板")
                 .doWrite(() -> {
                     // 动态查询或生成数据
                     return data();
                 });
 ​
         // 写法2
         // 直接传入数据源
         fileName = "EasyExcelDemo" + System.currentTimeMillis() + ".xlsx";
         // 同上,但是直接传入数据列表,而不是通过lambda表达式
         EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
     }

上传下载

UploadDownController

java 复制代码
 package com.baize.controller;
 ​
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.fastjson.JSON;
 import com.baize.config.DemoDataListener;
 import com.baize.entity.DemoData;
 import com.baize.service.DemoService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.multipart.MultipartFile;
 ​
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.util.*;
 ​
 @Controller
 public class UploadDownController {
 ​
     @Autowired
     private DemoService demoService;
 ​
     /**
      * 提供文件下载功能。特别注意,使用Swagger可能导致各种问题,建议使用浏览器或Postman进行测试。
      *
      * @param response 用于配置响应的HttpServletResponse对象,通过它将文件提供给客户端下载。
      * @throws IOException 如果在写入响应流时发生IO错误。
      */
     @GetMapping("download")
     public void download(HttpServletResponse response) throws IOException {
         // 设置响应内容类型为Excel文件
         response.setContentType("application/vnd.ms-excel");
         // 设置响应字符编码为UTF-8
         response.setCharacterEncoding("utf-8");
         // 对文件名进行URL编码,防止中文或其他特殊字符导致的乱码问题
         String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
         // 设置响应头,指定文件下载的名称和方式
         response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
         // 使用EasyExcel框架将数据写入响应输出流,以提供文件下载
         EasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(data());
     }
 ​
 ​
     /**
      * 文件下载接口。尝试下载一个Excel文件,如果失败,则返回一个包含错误信息的JSON。
      * 默认情况下,当下载失败时,会返回一个部分数据的Excel文件。
      *
      * @param response 用于响应客户端请求的HttpServletResponse对象。
      * @throws IOException 如果发生I/O错误。
      * @since 2.1.1
      */
     @GetMapping("api/download")
     public void downloadApi(HttpServletResponse response) throws IOException {
         try {
             // 设置响应类型为Excel文件,配置响应头以支持中文文件名
             response.setContentType("application/vnd.ms-excel");
             response.setCharacterEncoding("utf-8");
             String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
             response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
 ​
             // 使用EasyExcel框架写入Excel文件到响应输出流,不关闭流以保持连接
             EasyExcel.write(response.getOutputStream(), DemoData.class).autoCloseStream(Boolean.FALSE).sheet("模板")
                 .doWrite(data());
         } catch (Exception e) {
             // 下载失败时的处理:重置响应,返回JSON错误信息
             response.reset();
             response.setContentType("application/json");
             response.setCharacterEncoding("utf-8");
             Map<String, String> map = new HashMap<String, String>();
             map.put("code", "500");
             map.put("message", "下载文件失败" + e.getMessage());
             response.getWriter().println(JSON.toJSONString(map));
         }
     }
 ​
 ​
     /**
      * 文件上传接口。
      * 该方法接收一个文件,使用EasyExcel框架读取并处理文件内容。
      *
      * @param file 用户上传的文件,类型为MultipartFile。
      * @return 返回一个字符串表示上传结果,成功则返回"success"。
      * @throws IOException 如果读取文件发生错误,则抛出IOException。
      */
     @PostMapping("upload")
     @ResponseBody
     public String upload(MultipartFile file) throws IOException {
         // 使用EasyExcel框架读取上传文件的内容,并将其转换为DemoData对象,然后通过DemoDataListener处理这些对象
         EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener(demoService)).sheet().doRead();
         return "success";
     }
 ​
     /**
      * 生成包含10个DemoData对象的列表。
      * <p>此方法不接受任何参数。</p>
      *
      * @return 返回一个包含10个初始化的DemoData对象的列表。
      */
     private List<DemoData> data() {
         // 创建一个空的DemoData对象列表
         List<DemoData> list = new ArrayList<>();
         // 循环创建10个DemoData对象并填充数据,然后添加到列表中
         for (int i = 0; i < 10; i++) {
             DemoData data = new DemoData();
             // 为每个DemoData对象设置字符串属性
             data.setString("字符串" + 0);
             // 为每个DemoData对象设置当前日期
             data.setDate(new Date());
             // 为每个DemoData对象设置双精度浮点数属性
             data.setDoubleData(0.56);
             list.add(data);
         }
         return list;
     }
 }
复制代码
 ​

可以写工具类

java 复制代码
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.read.builder.ExcelReaderBuilder;
 import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
 import lombok.extern.slf4j.Slf4j;
 ​
 import java.io.InputStream;
 import java.util.List;
 ​
 @Slf4j
 public class ExcelUtils {
 ​
     /**
      * 从Excel文件中读取数据并将其转换为指定模型的列表。
      * 
      * @param inputStream Excel文件的输入流。
      * @param clazz 指定的模型类,用于将Excel单元格数据转换为该类型的对象。
      * @return 一个包含读取到的数据的列表,每个元素都是clazz指定的类型。
      * @throws NullPointerException 如果输入流为null,则抛出此异常。
      */
     public static <T> List<T> getExcelModelData(final InputStream inputStream, Class<T> clazz) {
         // 检查输入流是否为null
         if (null == inputStream) {
             throw new NullPointerException("the inputStream is null!");
         }
         // 使用EasyExcel框架初始化Excel读取构建器
         ExcelReaderBuilder result = EasyExcel.read(inputStream, clazz, null);
         // 获取默认工作表的构建器
         ExcelReaderSheetBuilder sheet1 = result.sheet();
         // 同步读取工作表数据并返回
         List<T> resultData = sheet1.doReadSync();
         return resultData;
     }
 }
相关推荐
热爱嵌入式的小许3 小时前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
yufei-coder5 小时前
掌握 C# 中的 LINQ(语言集成查询)
windows·vscode·c#·visual studio
韩楚风7 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学7 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO7 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu77 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我7 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、7 小时前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程7 小时前
Linux中环境变量
linux
我是哈哈hh8 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝