springboot excel 表格入门与实战

Spring Boot3 FastExcel 项目地址

https://gitee.com/supervol/loong-springboot-study

(记得给个start,感谢)

FastExcel 介绍

FastExcel 是一款轻量、高性能的 Java Excel 处理工具 ,核心目标是解决传统库(如 Apache POI)在大数据量场景下的内存溢出问题,同时提供简洁易用的 API。其官方核心定位如下:

  • 开源许可 :采用 Apache License 2.0,允许商业场景免费使用,无版权限制。
  • 跨 JDK 支持:兼容 JDK 8 ~ JDK 21(覆盖 Spring Boot 3 所需的 JDK 17+,同时支持旧项目)。
  • 底层依赖:基于 Apache POI 封装,但已优化内存模型;若项目已引入 POI,需手动排除冲突依赖。
  • 模块合并 :2025 年 7 月后已将 fastexcel-core 合并入核心模块 fastexcel

FastExcel 特性

功能分类 核心能力
高性能读写 优化内存模型,相比传统 POI 减少 60%+ 内存占用,支持百万级数据无 OOM。
流式处理 原生支持流式读取 / 写入,无需手动处理内存缓冲,数据逐行处理,降低内存峰值。
简洁 API 基于静态工厂类 FastExcel 封装,3 行代码即可实现 Excel 读写,无需关注底层 Sheet/Row/Cell 层级。
注解驱动 通过 @ExcelProperty 映射列与实体类,@ExcelIgnore 忽略无需导出的字段,配置零侵入。
扩展性 提供 ReadListener 监听读取过程(如数据校验、批量入库),支持自定义转换器。
多格式支持 兼容 .xlsx(Office 2007+)、.xls(兼容模式),无需额外配置格式类型。

FastExcel 示例

请参考项目地址中 springboot-office/springboot-excel 模块代码。

FastExcel 实战

FastExcel 官方核心 API 围绕 FastExcel 静态类展开,读取需实现 ReadListener,写入通过注解映射实体类,无复杂 Builder 嵌套。

1. 定义 Excel 映射实体类

使用官方注解 @ExcelProperty指定列名,@ExcelIgnore 忽略无需导出的字段:

java 复制代码
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.ExcelIgnore;
import java.util.Date;

// 官方示例实体类:用户数据
public class UserData {
    // @ExcelProperty:指定Excel列名,与表头完全匹配
    @ExcelProperty("用户ID")
    private Long userId;

    @ExcelProperty("用户名")
    private String username;

    // 日期类型无需额外配置格式(默认 yyyy-MM-dd HH:mm:ss,支持自动转换)
    @ExcelProperty("注册时间")
    private Date registerTime;

    // @ExcelIgnore:该字段不写入Excel,也不读取
    @ExcelIgnore
    private String password;

    // 省略 getter/setter(必须提供,否则无法映射)
}

2. 读取 Excel 文件

通过 实现 ReadListener 接口 处理读取逻辑(支持数据逐行回调,避免一次性加载内存),适用于本地文件或 HTTP 上传文件。

(1) 实现 ReadListener
java 复制代码
import cn.idev.excel.listener.ReadListener;
import cn.idev.excel.context.AnalysisContext;
import java.util.ArrayList;
import java.util.List;

// 自定义读取监听器:处理Excel每行数据
public class UserDataListener implements ReadListener<UserData> {
    // 批量存储读取到的数据(可根据业务设置批量大小,如1000条入库一次)
    private List<UserData> dataList = new ArrayList<>(1000);

    // 逐行回调:每读取一行数据,触发该方法
    @Override
    public void invoke(UserData userData, AnalysisContext context) {
        // 1. 数据校验(示例:用户名不能为空)
        if (userData.getUsername() == null || userData.getUsername().trim().isEmpty()) {
            throw new RuntimeException("第" + context.getRowNum() + "行:用户名不能为空");
        }
        // 2. 加入临时列表
        dataList.add(userData);
        // 3. 批量处理(示例:满1000条入库,避免列表过大)
        if (dataList.size() >= 1000) {
            saveBatchData(); // 调用业务方法批量入库
            dataList.clear(); // 清空列表,释放内存
        }
    }

    // 读取完成后回调:所有数据读取完毕后触发
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 处理剩余数据(不足1000条的部分)
        if (!dataList.isEmpty()) {
            saveBatchData();
        }
        System.out.println("Excel读取完成,共处理" + context.getTotalRowNum() + "行数据");
    }

    // 业务方法:批量保存数据(示例,需结合DAO层实现)
    private void saveBatchData() {
        // userMapper.batchInsert(dataList); // MyBatis批量入库示例
        System.out.println("批量保存" + dataList.size() + "条用户数据");
    }
}
(2) 发起读取

场景 A:读取本地 Excel 文件

java 复制代码
import cn.idev.excel.FastExcel;
import org.springframework.stereotype.Service;

@Service
public class ExcelImportService {
    // 读取本地Excel文件(路径示例:D:/data/user_import.xlsx)
    public void importLocalExcel(String filePath) {
        // 官方读取API:FastExcel.read(文件路径, 实体类, 监听器).sheet().doRead()
        FastExcel.read(filePath, UserData.class, new UserDataListener())
                .sheet() // 读取第一个工作表(默认索引0,可指定名称:.sheet("用户导入表"))
                .doRead(); // 执行读取
    }
}

场景 B:读取 HTTP 上传文件

java 复制代码
import cn.idev.excel.FastExcel;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;

@RestController
public class ExcelImportController {
    // 接收前端上传的Excel文件
    @PostMapping("/api/excel/import/user")
    public String importUser(@RequestParam("file") MultipartFile file) throws IOException {
        // 1. 校验文件格式
        String fileName = file.getOriginalFilename();
        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
            return "错误:仅支持 .xlsx 或 .xls 格式";
        }

        // 2. 读取上传文件流(无需手动关闭流,FastExcel内部自动处理)
        FastExcel.read(file.getInputStream(), UserData.class, new UserDataListener())
                .sheet()
                .doRead();

        return "导入成功,文件大小:" + file.getSize() + "字节";
    }
}

3. 写入 Excel 文件

写入 API 极简,通过 FastExcel.write() 直接生成文件,支持流式写入大数据量(无需手动开启,内部自动判断)。Spring Boot 响应式下载示例代码。

java 复制代码
import cn.idev.excel.FastExcel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

@RestController
public class ExcelExportController {
    private final UserService userService; // 业务层:查询用户数据

    // 构造注入(Spring Boot 3 推荐)
    public ExcelExportController(UserService userService) {
        this.userService = userService;
    }

    // 导出用户数据为Excel,浏览器直接下载
    @GetMapping("/api/excel/export/user")
    public void exportUser(HttpServletResponse response) throws IOException {
        // 1. 准备导出数据(模拟大数据量,如10万条)
        List<UserData> userList = userService.listAllUsers(); // 业务查询(建议分页查询避免内存占用)

        // 2. 设置响应头(指定下载格式、文件名)
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        // 文件名编码:避免中文乱码
        String fileName = URLEncoder.encode("用户数据导出_2025.xlsx", "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

        // 3. 官方写入API:流式写入响应流
        FastExcel.write(response.getOutputStream(), UserData.class)
                .sheet("用户列表") // 指定工作表名称
                .doWrite(userList); // 执行写入(内部自动流式处理,无OOM风险)
    }
}

4. 自定义读取 / 写入配置

支持自定义工作表索引、表头行数、数据转换器等,通过链式调用扩展配置:

(1) 自定义读取配置

java 复制代码
// 读取第2个工作表(索引1),跳过前2行(表头在第3行)
FastExcel.read(filePath, UserData.class, new UserDataListener())
        .sheet(1) // 工作表索引(0开始),也可指定名称:.sheet("2025年用户")
        .headRowNumber(2) // 表头行数(默认1行,即第1行为表头,此处表示前2行为说明,第3行为表头)
        .doRead();

(2) 自定义日期格式

java 复制代码
import cn.idev.excel.converter.LocalDateTimeConverter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

// 示例:自定义LocalDateTime格式为 "yyyy年MM月dd日 HH:mm"
public class CustomDateTimeConverter extends LocalDateTimeConverter {
    public CustomDateTimeConverter() {
        super(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm"));
    }
}

// 实体类中使用自定义转换器
public class UserData {
    @ExcelProperty(value = "最后登录时间", converter = CustomDateTimeConverter.class)
    private LocalDateTime lastLoginTime;
    // 其他字段...
}

FastExcel 注意

  1. POI 依赖冲突 :FastExcel 内部依赖 POI 4.4.0+,若项目已引入旧版 POI(如 3.x),需手动排除冲突,否则会出现 NoSuchMethodError
  2. 实体类要求 :映射实体类必须提供 无参构造器getter/setter(FastExcel 通过反射获取字段值,缺少会导致映射失败)。
  3. 大数据量建议 :导出超过 100 万条数据时,建议结合 分页查询 (如 MyBatis 分页),分批次调用 doWrite()(示例:每次写入 10 万条,避免一次性查询全量数据)。
  4. 文件权限 :读取本地文件时,确保应用有文件读取权限;写入临时文件时,避免使用系统敏感路径(如 /root)。
相关推荐
大模型码小白1 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司2 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地3 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
莫逸风5 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
隔窗听雨眠5 小时前
Spring Boot在云原生时代的编程范式革新研究
spring boot·后端·云原生
z123456789866 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
yaoxin5211236 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python
做个文艺程序员7 小时前
Linux第24篇:Java应用监控体系搭建:Prometheus+Grafana可视化运维
java·grafana·prometheus
小钻风33667 小时前
Spring Boot 文件上传详解:深入理解 MultipartFile 的使用与原理
java·开发语言
其美杰布-富贵-李8 小时前
Spring Boot 工程开发全流程说明
java·spring boot·后端