【微服务】SpringBoot 整合 FastExcel 实现导入导出操作详解

目录

一、前言

[二、FastExcel 介绍](#二、FastExcel 介绍)

[2.1 FastExcel 是什么](#2.1 FastExcel 是什么)

[2.2 FastExcel 主要特点](#2.2 FastExcel 主要特点)

[2.3 FastExcel 主要功能](#2.3 FastExcel 主要功能)

[2.4 FastExcel 核心技术实现原理](#2.4 FastExcel 核心技术实现原理)

[三、springboot 整合FastExcel 操作过程](#三、springboot 整合FastExcel 操作过程)

[3.1 开发环境准备](#3.1 开发环境准备)

[3.2 完整整合过程](#3.2 完整整合过程)

[3.2.1 添加依赖](#3.2.1 添加依赖)

[3.2.2 配置文件信息](#3.2.2 配置文件信息)

[3.2.3 增加一个实体类](#3.2.3 增加一个实体类)

[3.2.4 增加一个事件监听器](#3.2.4 增加一个事件监听器)

[3.2.5 增加一个测试使用的接口类](#3.2.5 增加一个测试使用的接口类)

[3.2.6 效果测试与验证](#3.2.6 效果测试与验证)

[3.2.7 补充说明](#3.2.7 补充说明)

[3.3 FastExcel 高级功能](#3.3 FastExcel 高级功能)

[3.3.1 大量数据导入优化](#3.3.1 大量数据导入优化)

[3.3.2 excel转pdf功能](#3.3.2 excel转pdf功能)

[3.4 EasyExcel 升级到FastExcel](#3.4 EasyExcel 升级到FastExcel)

[3.4.1 修改依赖](#3.4.1 修改依赖)

[3.4.2 修改代码](#3.4.2 修改代码)

四、写在文末


一、前言

在微服务项目中经常会涉及到excel的导入导出功能,随着要处理的业务数据量越来越大,这也对程序提出了更高的要求,因为大批量的数据导入导出对性能提出了更高的挑战。在早些年使用poi等工具进行导入导出的时候,经常会被吐槽有各种问题,比如API使用复杂,数据量过大时容易OOM等问题,所以在后面当EasyExcel推出来之后,其优异的性能得到了很多程序开发者的认可。可惜的是,随着EasyExcel的设计者离场,EasyExcel的维护面临着考验,于是又推出FastExcel 。作为EasyExcel的替代者,不仅完全兼容EasyExcel的功能,同时也对其进行了进一步的优化,并增加了一些新的功能,本篇将详细介绍下FastExcel 的使用。

二、FastExcel 介绍

2.1 FastExcel 是什么

FastExcel 是一款基于 Java 的开源库,旨在提供快速、简洁且能解决大文件内存溢出问题的 Excel 处理工具。它兼容 EasyExcel,提供性能优化、bug 修复,并新增了如读取指定行数和将 Excel 转换为 PDF 的功能。

FastExcel 以 MIT 协议发布,适用于任何商业场景。其高性能读写、简单易用的 API 和流式操作能力,使其特别适合处理大规模数据。FastExcel 支持无缝从 EasyExcel 迁移,极大地简化了 Excel 文件的读写操作,提升了开发效率。git地址:GitHub - apache/fesod: Fast. Easy. Done. Processing Excels without worrying about large files causing OOM.

2.2 FastExcel 主要特点

FastExcel 具备如下特点:

  • 完全兼容EasyExcel的所有功能和特性,这使得用户可以无缝迁移和过渡;

  • 从EasyExcel升级到EasyExcel,只需要简单的更换包名和maven依赖即可完成成升级;

  • 从功能上,比EasyExcel提供更多创新改进,比如 FastExcel 1.0.0版本新增了:

    • 读取excel指定的行数;

    • 将excel转为pdf;

2.3 FastExcel 主要功能

FastExcel 主要提供了以下功能

  • 高性能读写:FastExcel 专注于性能优化,能高效处理大规模 Excel 数据,显著降低内存占用。

  • 简单易用:提供简洁直观的 API,易于集成和使用。

  • 流式操作:支持流式读取,减少一次性加载大量数据的问题。

  • 读取指定行数:可以根据需求,只读取感兴趣的部分数据,提高数据处理效率。

  • Excel 转换为 PDF:支持直接将 Excel 文件转换为 PDF,满足多样化的文档输出需求。

2.4 FastExcel 核心技术实现原理

FastExcel 核心原理参考下面的理解:

  • 内存优化:基于流式读取技术,不需要一次性将整个 Excel 文件加载到内存中,逐行或逐块读取数据。

  • 事件驱动模型 :基于实现 ReadListener 接口处理读取操作。当读取到数据时,会触发接口中的方法,如 invoke 方法,支持开发者对每行数据进行即时处理。

  • 注解映射:用注解将 Excel 文件中的列与 Java 对象的属性进行映射。开发者能轻松地将 Excel 数据转换为 Java 对象,同时也支持反向操作,将 Java 对象写入 Excel。

三、springboot 整合FastExcel 操作过程

接下来通过实际案例演示下如何在springboot 项目中整合FastExcel 。

3.1 开发环境准备

为了确保后续你的工程也能正常的使用,建议参考下面的技术栈:

  1. JDK 17;

  2. SpringBoot 3.3 ;

3.2 完整整合过程

3.2.1 添加依赖

创建一个全新的springboot工程,在pom文件中添加如下的依赖

java 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.3</version>
    <relativePath/>
</parent>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>cn.idev.excel</groupId>
        <artifactId>fastexcel</artifactId>
        <version>1.0.0</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

</dependencies>

3.2.2 配置文件信息

本例仅演示导入导出功能,配置文件只需要配置下端口即可

java 复制代码
server:
  port: 8082

3.2.3 增加一个实体类

之前有使用过easyexcel经验的同学应该不陌生,一般导入的数据最终需要落库,为了让excel的列与数据库表字段进行对应,一般需要一个自定义的对象,用easyexcel提供的相应注解来标准字段信息,这样easyexcel在解析的时候才能进行映射,如下,增加一个自定义的User类,里面有3个基本属性

java 复制代码
package com.congge.entity;

import cn.idev.excel.annotation.ExcelProperty;
import lombok.*;

@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @ExcelProperty("编号")
    private Integer id;

    @ExcelProperty("名字")
    private String name;

    @ExcelProperty("年龄")
    private Integer age;
}

3.2.4 增加一个事件监听器

监听器的作用也可以理解为FastExcel 内部封装的一个兼具数据读取,数据缓存,数据转换为一体的组件,有了这个监听器,上层只需要在上传或下载excel的时候代入进去,该监听器就可以发挥作用,从而完成数据的转换。参考下面的代码。

java 复制代码
package com.congge.component;

import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;

import java.util.ArrayList;
import java.util.List;

public class BaseExcelListener<T> extends AnalysisEventListener<T> {

    private final List<T> dataList = new ArrayList<>();

    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        // 每读取一行数据,就将其添加到dataList中
        dataList.add(t);
        System.out.println("解析到数据: " + t);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        System.out.println("读取完成,共读取了 " + dataList.size() + " 条数据");
    }

    public List<T> getDataList() {
        return dataList;
    }
}

3.2.5 增加一个测试使用的接口类

为了方便测试看效果,增加一个controller控制器类,提供2个基本的上传下载接口,参考下面的代码

java 复制代码
package com.congge.controller;

import cn.idev.excel.FastExcel;
import com.congge.component.BaseExcelListener;
import com.congge.entity.User;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

@RestController
@RequestMapping("/api/excel")
public class ExcelController {

    /**
     * Excel导出功能
     * @param response
     * @throws IOException
     * localhost:8082/api/excel/download
     */
    @GetMapping("/download")
    public void download(HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("用户数据", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        // 写入数据
        FastExcel.write(response.getOutputStream(), User.class)
                .sheet("用户信息")
                .doWrite(buildData());
    }

    /**
     * Excel导出功能
     * @param file
     * @return
     * localhost:8082/api/excel/upload
     */
    @PostMapping("/upload")
    public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return ResponseEntity.badRequest().body("请选择一个文件上传!");
        }
        try {
            BaseExcelListener<User> baseExcelListener = new BaseExcelListener<>();
            FastExcel.read(file.getInputStream(), User.class, baseExcelListener)
                    .sheet()
                    .doRead();
            // 获取读取的数据
            List<User> dataList = baseExcelListener.getDataList();
            System.out.println("读取到的数据: " + dataList);
            return ResponseEntity.ok("文件上传并处理成功!共处理 " + dataList.size() + " 条数据");
        } catch (IOException e) {
            return ResponseEntity.status(500).body("文件处理失败: " + e.getMessage());
        }
    }

    // 创建测试数据
    private List<User> buildData() {
        User user1 = new User();
        user1.setId(1);
        user1.setName("张三");
        user1.setAge(18);

        User user2 = new User();
        user2.setId(2);
        user2.setName("李四");
        user2.setAge(19);

        return List.of(user1, user2);
    }
}

3.2.6 效果测试与验证

分别测试一下上面两个接口,启动工程

1)下载接口测试

启动工程后,浏览器调用接口:localhost:8082/api/excel/download *,*按照预期的效果下载为一个excel

2)上传接口测试

使用接口工具模拟接口调用,就用上面的这个excel,主要是看看控制台的输出日志,接口调用成功

通过控制台的输出日志可以看到,待导入的数据也成功进行了加载

3.2.7 补充说明

有的同学可能会有这样的担心,当excel数据量太大的时候,会不会有性能问题,关于这一点,FastExcel 的作者在设计的时候就考虑到了,当你要上传的excel里面的数据量比较大,工具方法内部会进行分批读取,从而减少OOM的风险

3.3 FastExcel 高级功能

3.3.1 大量数据导入优化

对于大数据量导入,建议使用批量处理模式,因此需要改写和优化上述的事件监听器,参考下面的代码

java 复制代码
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;

public class BatchExcelListener<T> extends AnalysisEventListener<T> {
    private static final int BATCH_COUNT = 1000;
    private List<T> dataList = new ArrayList<>(BATCH_COUNT);
    
    @Override
    public void invoke(T data, AnalysisContext context) {
        dataList.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (dataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            dataList = new ArrayList<>(BATCH_COUNT);
        }
    }
    
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 确保最后遗留的数据也存储到数据库
        if (!dataList.isEmpty()) {
            saveData();
        }
        System.out.println("所有数据解析完成!");
    }
    
    private void saveData() {
        // 这里实现批量保存到数据库的逻辑
        System.out.println("批量保存" + dataList.size() + "条数据到数据库");
        // userService.saveBatch(dataList);
    }
}

3.3.2 excel转pdf功能

添加下面的测试接口验证excel转pdf功能

java 复制代码
//localhost:8082/api/excel/convertToPdf
@GetMapping("/convertToPdf")
public void convertToPdf(){
    String excelPath = "D:\\data\\用户数据.xlsx";
    String pdfFilePath = "D:\\data\\用户数据.pdf";
    FastExcel.convertToPdf(new File(excelPath), new File(pdfFilePath), null, null);
    System.out.println("转换完成");
}

3.4 EasyExcel 升级到FastExcel

有一些伙伴之前项目中使用的是EasyExcel ,那么如果要升级到FastExcel该怎么做呢,可以参考下面的步骤

3.4.1 修改依赖

将 EasyExcel 的依赖替换为 FastExcel 的依赖,如下:

java 复制代码
<!-- easyexcel 依赖 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>easyexcel</artifactId>
  <version>xxxx</version>
</dependency>

依赖替换为:

java 复制代码
<dependency>
  <groupId>cn.idev.excel</groupId>
  <artifactId>fastexcel</artifactId>
  <version>1.0.0</version>
</dependency>

3.4.2 修改代码

将 EasyExcel 的包名替换为 FastExcel 的包名,如下:

java 复制代码
// 将 easyexcel 的包名替换为 FastExcel 的包名
import com.alibaba.excel.**;

替换为:

java 复制代码
import cn.idev.excel.**;

四、写在文末

本文通过案例代码演示了FastExcel 的使用,通过案例介绍了FastExcel 具体的导入导出的使用,更多功能有兴趣的同学可以继续深入研究,本篇到此结束,感谢观看。

相关推荐
假客套3 天前
2025 FastExcel在Java的Maven项目的导出和导入,简单易上手,以下为完整示例
java·maven·fastexcel
kangaroo.16 天前
基于EasyExcel、FastExcel封装spring boot starter
spring boot·easyexcel·fastexcel
程序猿七度2 个月前
【FastExcel】解决ReadSheet在Map中获取对象不准确问题(已提交PR并合并到开源社区)
java·开源·fastexcel
智_永无止境3 个月前
FastExcel:革新Java生态的高性能Excel处理引擎
java·excel·fastexcel
NiNg_1_2349 个月前
FastExcel使用详解
开发语言·excel·fastexcel
Hello Dam9 个月前
基于 FastExcel 与消息队列高效生成及导入机构用户数据
java·数据库·spring boot·excel·easyexcel·fastexcel
菠萝蚊鸭10 个月前
Dhatim FastExcel 读写 Excel 文件
java·excel·fastexcel
❀͜͡傀儡师10 个月前
EasyExcel改名为FastExce做了那些改变呢
java·fastexcel