Java SpringBoot使用EasyExcel导入导出Excel文件

点击下载《Java SpringBoot使用EasyExcel导入导出Excel文件(源代码)》

在 Java Spring Boot 项目中,导入(读取)和导出(写入) Excel 文件是一项常见的需求。EasyExcel 是阿里巴巴开源的一个用于简化 Java 环境下 Excel 文件读取和写入操作的库。相比于传统的 Apache POI,EasyExcel 在性能和易用性方面进行了优化,特别适用于处理大规模 Excel 文件。

1. EasyExcel 介绍

1.1 EasyExcel 的特点

特性/方面 详细说明
基于事件驱动的解析 采用 SAX 解析方式,通过事件驱动逐行读取 Excel 数据,避免将整个文件加载到内存中,降低内存消耗。
内存友好 由于逐行读取和处理数据,内存占用极低,适合处理大型 Excel 文件,避免内存溢出问题。
简洁易用的 API 提供高度封装的 API,通过注解(如 @ExcelProperty)轻松实现 Java 对象与 Excel 列的映射,减少样板代码的编写。
支持多种数据格式 支持常见的 Excel 数据格式,包括 .xlsx.xls 文件,并支持自定义数据格式转换。
丰富的功能 支持读取和写入 Excel 文件、自定义转换器、多工作表操作、注解支持、异常处理等。
高性能 在处理大规模数据时表现出色,能够显著提高数据导入和导出的效率。
社区活跃 作为阿里巴巴开源项目,拥有活跃的社区和及时的更新,能够及时修复问题和添加新功能。
依赖其他库 依赖于 cglib 和其他一些库,如果项目中已经使用了不同版本的这些库,可能会导致版本冲突。
学习曲线 虽然 API 简洁,但对于不熟悉事件驱动编程或注解映射的开发者,可能需要一定的学习成本。
功能相对有限 与 Apache POI 相比,EasyExcel 对公式、图表、样式等复杂功能的支持相对较少。
灵活性高 支持自定义数据转换器、多工作表操作等功能,提供了高度的灵活性以满足不同的业务需求。

1.2 EasyExcel 的优点

优点 详细说明
内存效率高 采用事件驱动和逐行读取的方式,内存占用低,适合处理大型 Excel 文件,避免内存溢出问题。
性能优越 在处理大规模数据时具有更高的性能,能够显著减少处理时间,提高数据导入和导出效率。
易用性强 通过简洁的 API 和注解支持,简化了 Excel 数据的读取和写入操作,减少了代码量,提高了开发效率。
灵活性高 支持自定义数据转换器、多工作表操作等功能,能够满足不同的业务需求。
社区支持 作为开源项目,拥有活跃的社区和及时的更新,能够及时响应用户需求和问题。

1.3 EasyExcel 的缺点

缺点 详细说明
功能相对有限 与 Apache POI 相比,EasyExcel 对公式、图表、样式等复杂功能的支持较少。
依赖其他库 依赖于 cglib 和其他一些库,可能导致版本冲突,需要注意依赖管理。
学习曲线 对于不熟悉事件驱动编程或注解映射的开发者,可能需要一定的学习成本。
社区规模 虽然拥有活跃的社区,但与 Apache POI 相比,社区规模相对较小,可能在某些情况下获取帮助的渠道相对有限。

2. EasyExcel使用

2.1 引入 EasyExcel 依赖

首先,需要在 pom.xml 中引入 EasyExcel 的依赖:

xml 复制代码
<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- EasyExcel 依赖 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel-core</artifactId>
        <version>3.1.2</version>
    </dependency>

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version> <!-- 请检查最新版本 -->
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>

    <!-- 其他依赖 -->
</dependencies>

2.2 定义数据模型

使用 EasyExcel 导入导出数据时,需要定义与 Excel 列对应的 Java 类,并使用注解标注列信息。

java 复制代码
package com.yyqq.exceldemo.model;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

@Data
public class UserData {

    @ExcelProperty("编号") // Excel 中的列名
    private Integer id;

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

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

    @ExcelProperty("邮箱")
    private String email;
}

说明

  • @Data:Lombok 提供的注解,用于自动生成 getter、setter、toString 等方法。
  • @ExcelProperty:指定 Excel 中对应的列名。

2.3 Excel 导入导出Controller类

java 复制代码
package com.yyqq.exceldemo.controller;

import com.alibaba.excel.EasyExcel;
import com.yyqq.exceldemo.model.UserData;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@RestController
public class ExcelController {

    /**
     * 导入execl文件
     */
    @GetMapping("/export")
    public ResponseEntity<byte[]> exportExcel() {
        String fileName = "用户数据.xlsx";
        List<UserData> userList = generateUserData();

        // EasyExcel 写入到字节数组
        byte[] bytes = exportToExcel(userList);

        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", fileName);

        return ResponseEntity.ok()
                .headers(headers)
                .body(bytes);
    }

    @PostMapping("/import")
    public String importExcel(@RequestParam("file") MultipartFile file) {
        try {
            InputStream inputStream = file.getInputStream();
            // 使用 EasyExcel 读取 Excel 数据
            List<UserData> userList = EasyExcel.read(inputStream)
                    .head(UserData.class)
                    .sheet()
                    .doReadSync();

            // 处理导入的数据,例如保存到数据库
            processUserData(userList);

            return "导入成功,共导入 " + userList.size() + " 条数据";
        } catch (Exception e) {
            e.printStackTrace();
            return "导入失败: " + e.getMessage();
        }
    }

    /**
     * 模拟生产用户数据
     * @return
     */
    private List<UserData> generateUserData() {
        List<UserData> list = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            UserData user = new UserData();
            user.setId(i);
            user.setName("用户" + i);
            user.setAge(20 + i % 30);
            user.setEmail("user" + i + "@example.com");
            list.add(user);
        }
        return list;
    }

    /**
     * 将数据导出至byte数组中
     */
    private byte[] exportToExcel(List<UserData> userList) {
        // 使用 EasyExcel 写入 Excel 到字节数组
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        EasyExcel.write(out, UserData.class)
                .sheet("用户数据")
                .doWrite(userList);
        return out.toByteArray();
    }

    /**
     * 导入数据方法
     */
    private List<UserData> importFromExcelWithPOI(MultipartFile file) {
        List<UserData> userList = new ArrayList<>();
        try (InputStream inputStream = file.getInputStream();
             Workbook workbook = WorkbookFactory.create(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
            Iterator<Row> iterator = sheet.iterator();

            // 跳过表头
            if (iterator.hasNext()) {
                iterator.next();
            }

            while (iterator.hasNext()) {
                Row row = iterator.next();
                UserData user = new UserData();
                user.setId((int) row.getCell(0).getNumericCellValue());
                user.setName(row.getCell(1).getStringCellValue());
                user.setAge((int) row.getCell(2).getNumericCellValue());
                user.setEmail(row.getCell(3).getStringCellValue());
                userList.add(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return userList;
    }

    private void processUserData(List<UserData> userList) {
        // 这里可以添加将数据保存到数据库的逻辑
        // 例如使用 JPA 或 MyBatis 等持久层框架
        userList.forEach(user -> {
            // 模拟保存操作
            System.out.println("保存用户: " + user);
        });
    }
}

2.4 编写测试html文件

在src/main/resources/static目录创建import.html文件,代码如下:

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>Excel 导入</title>
</head>
<body>
<h1>导入 Excel 文件</h1>
<form method="POST" enctype="multipart/form-data" action="/import">
    <input type="file" name="file" accept=".xlsx, .xls" />
    <button type="submit">上传</button>
</form>
</body>
</html>

export导出接口说明

  • 导出接口/export 接口返回 Excel 文件。
  • generateUserData() 方法:生成示例用户数据。
  • exportToExcel() 方法
    • 使用 EasyExcel 的 write 方法将数据写入 ByteArrayOutputStream
    • sheet("用户数据") 指定工作表名称。
    • doWrite(userList) 写入数据列表。
  • 启动 Spring Boot 应用后,访问 http://localhost:8080/export,即可下载生成的 Excel 文件。

import导入接口说明

  • 导入接口/import 接口接收 Excel 文件并处理。
  • 导入逻辑
    • 使用 EasyExcel 的 read 方法读取上传的 Excel 文件。
    • head(UserData.class) 指定数据模型类。
    • sheet() 指定读取的工作表。
    • doReadSync() 同步读取数据。
  • processUserData() 方法:处理导入的数据,例如保存到数据库。
  • 使用Postman调用接口
  • 或者直接在浏览器中输入地址:http://127.0.0.1:8080/import.html,然后上传一个excel文件:

    结果如下:

3. 总结

EasyExcel 是一个高性能、易用性强的 Java 库,适用于处理大规模 Excel 文件的导入和导出操作。其基于事件驱动的解析方式、内存友好的特性以及简洁的 API 使得开发者能够高效地完成数据处理任务。然而,在需要处理复杂 Excel 功能(如公式、图表、样式等)时,EasyExcel 的功能可能相对有限。对于大多数常见的 Excel 操作需求,EasyExcel 是一个非常不错的选择,但在特定场景下,可能需要结合使用其他库或工具。

点击下载《Java SpringBoot使用EasyExcel导入导出Excel文件(源代码)》

相关推荐
啊烨疯狂学java7 分钟前
0105java字节面经
java·jvm·算法
我命由我1234523 分钟前
27.Java 线程间通信(synchronized 实现线程间通信、Lock 实现线程间通信)
java·开发语言·后端·java-ee·intellij-idea·juc·后端开发
迪小莫学AI24 分钟前
# LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game)
java·linux·leetcode
星辰大海的精灵26 分钟前
SpringBoot 整合 Elastic-Job 实现任务分布式调度
java·spring boot·后端
Q_192849990635 分钟前
基于Spring Boot微信小程序电影管理系统
spring boot·后端·微信小程序
子非鱼@Itfuture1 小时前
Spark是什么?Flink和Spark区别
java·大数据·数据仓库·python·flink·spark
NHuan^_^1 小时前
RabbitMQ基础篇之Java客户端 Work Queues
java·rabbitmq·java-rabbitmq
九州~空城1 小时前
C++中map和set的封装
java·前端·c++
工一木子1 小时前
【HeadFirst系列之HeadFirst设计模式】第1天之HeadFirst设计模式开胃菜
java·设计模式·headfirst设计模式
StevenGerrad1 小时前
【读书笔记/源码】How Tomcat Works 笔记- c11~c13
java·笔记·tomcat