java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > FastExcel导入导出

SpringBoot整合FastExcel实现导入导出功能的操作详解

作者:小码农叔叔

在微服务项目中经常会涉及到excel的导入导出功能,随着要处理的业务数据量越来越大,这也对程序提出了更高的要求,下面我们就来看看SpringBoot如何整合FastExcel实现导入导出功能吧

一、前言

在微服务项目中经常会涉及到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版本新增了:

2.3 FastExcel 主要功能

FastExcel 主要提供了以下功能

2.4 FastExcel 核心技术实现原理

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

三、springboot 整合FastExcel 操作过程

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

3.1 开发环境准备

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

3.2 完整整合过程

3.2.1 添加依赖

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

<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 配置文件信息

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

server:
  port: 8082

3.2.3 增加一个实体类

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

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的时候代入进去,该监听器就可以发挥作用,从而完成数据的转换。参考下面的代码。

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个基本的上传下载接口,参考下面的代码

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 大量数据导入优化

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

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功能

//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 的依赖,如下:

<!-- easyexcel 依赖 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>easyexcel</artifactId>
  <version>xxxx</version>
</dependency>

依赖替换为:

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

3.4.2 修改代码

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

// 将 easyexcel 的包名替换为 FastExcel 的包名
import com.alibaba.excel.**;

替换为:

import cn.idev.excel.**;

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

到此这篇关于SpringBoot整合FastExcel实现导入导出功能的操作详解的文章就介绍到这了,更多相关SpringBoot FastExcel导入导出内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文