EasyExcel的使用

作者:脸大是真的好~日期:2026/2/15

需求1:能够导出1个Excel文件,能够导入一个Excel文件;
需求2:导出的文件,能实现第1行,第123列的合并单元格:也就是会写注册处理器;知道sheet和cell是什么;
需求3:能实现合并的单元格设置单元格宽高,背景颜色,内容居中,字体大小;
需求4:能控制从任意行开始写入,并让要输出的字段居中;
需求5:导出能实现从任意行开始读入;

导出Excel文件

1<!-- EasyExcel 核心依赖 -->
2<dependency>
3    <groupId>com.alibaba</groupId>
4    <artifactId>easyexcel</artifactId>
5    <version>3.3.4</version>
6</dependency>
7
1//  @Data 简化 getter/setter(需引入 lombok 依赖,也可手动写)
2@Data
3@NoArgsConstructor
4@AllArgsConstructor
5// 表头居中 + 内容居中(核心注解)
6@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER)
7@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER)
8public class UserData {
9
10    // @ExcelProperty 注解指定 Excel 列名
11    @ExcelProperty("用户ID")
12    private Long id;
13
14    @ExcelProperty("姓名")
15    private String name;
16
17    @ExcelProperty("年龄")
18    private Integer age;
19}
20
1@RestController
2public class ExcelExportController {
3    @PostMapping("/excelExport")
4    public void excelExport() throws IOException {
5        // 1.获取当前时间,作文件名拼接使用
6        String formattedNow = getFormattedNow();
7
8        // 2. 指定生成的 Excel 文件路径和名称
9        String filePath = "C:\\Users\\59742\\Desktop\\IdeaProjects\\ExcelImportExport\\excelFiles/excel_" + formattedNow + ".xlsx";
10
11        // 3. 准备要写入的数据
12        List<UserData> dataList = new ArrayList<>();
13        for (int i = 0; i < 5; i++) {
14            UserData user = new UserData();
15            user.setId((long) i);
16            user.setName("用户" + i);
17            user.setAge(20 + i);
18            dataList.add(user);
19        }
20
21        // 4.写入Excel文件
22        EasyExcel.write(filePath, UserData.class)
23                .sheet("用户信息表")
24                .relativeHeadRowIndex(1) // 默认为0行,这里从第一行开始写入
25                // 有什么要对表格进行的操作,可以使用注册自定义的处理器
26                .registerWriteHandler(new MergeCellWriteHandler())//合并单元格
27                .doWrite(dataList);
28        System.out.println("Excel 文件生成成功!路径为:" + filePath);
29    }
30
31    /**
32     * 获取当前时间,格式化输出
33     * @return
34     */
35    private static String getFormattedNow() {
36        // 获取当前时间
37        LocalDateTime now = LocalDateTime.now();
38        // 格式化输出(推荐使用 DateTimeFormatter,取代 SimpleDateFormat)
39        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss");
40        return now.format(formatter);
41    }
42}
43
1/**
2 * 自定义单元格合并处理器(核心)
3 * 实现 SheetWriteHandler接口,拦截单元格写入事件
4 */
5public class MergeCellWriteHandler implements SheetWriteHandler {
6
7    @Override
8    public void afterSheetCreate(SheetWriteHandlerContext context) {
9        // 1.想操作excel表,第一步是拿到表里的sheet
10        Sheet sheet = context.getWriteSheetHolder().getSheet();
11        // 2.拿到sheet,然后操作里面的每一个格子(CELL),然后调用合并单元格方法:addMergedRegion(),然后new一个范围性的cellRangeAddress()
12        //  sheet 创建后立即合并 A1:C1(第0行,列0~2)
13        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 2));
14        sheet.createRow(0)
15                .createCell(0)
16                .setCellValue("提示:姓名和年龄是必填的");
17
18        // 样式设置
19        // 1.设置合并单元格的宽和高
20        sheet.setColumnWidth(0, 30 * 256);
21        sheet.setColumnWidth(1, 30 * 256);
22        sheet.setColumnWidth(2, 30 * 256);
23        sheet.getRow(0).setHeightInPoints(200);
24
25        // 设置单元格的背景颜色
26        // 1. 先创建样式对象并设置属性(必须分步,无法纯链式)
27        CellStyle style = sheet.getWorkbook().createCellStyle();
28        style.setFillForegroundColor(IndexedColors.BRIGHT_GREEN1.getIndex());
29        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
30
31        // 2. 设置单元格内容居中
32        style.setAlignment(HorizontalAlignment.CENTER); // 水平居中
33        style.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
34
35        // 3. 设置单元格字体大小
36        Font font = sheet.getWorkbook().createFont();
37        font.setFontHeightInPoints((short) 32);
38        style.setFont(font);
39
40        // 4. 给单元格绑定样式
41        sheet.getRow(0).getCell(0).setCellStyle(style);
42    }
43}
44

在这里插入图片描述

导入Excel文件

1@RestController
2public class ImportExcelController {
3
4    @PostMapping("/excelImport")
5    public void excelImport(MultipartFile file) throws IOException {
6
7        System.out.println("开始导入");
8        ExcelImportListener listener = new ExcelImportListener();
9        // 核心:读取 Excel
10        EasyExcel.read(file.getInputStream(), UserData.class, listener)
11                .sheet("用户信息表")  // 指定要读取的工作表
12                .headRowNumber(2) // 这里代表索引2,第3行开始读取
13                .doRead(); // 执行读取
14
15        // 获取读取到的数据并打印
16        System.out.println("最终读取到的数据:" + listener.getDataList());
17    }
18}
19

成功读取到数据
在这里插入图片描述
在这里插入图片描述

  • 每读取一行,调用invoke一次!!!!
1
2// 加Slf4j方便打印日志(也可以用System.out)
3@Slf4j
4public class ExcelImportListener extends AnalysisEventListener<UserData> {
5
6    // 存储读取到的所有数据(适合小文件,大文件建议批量处理)
7    private List<UserData> dataList = new ArrayList<>();
8
9    /**
10     * 核心方法:每读取一行Excel数据,就会调用这个方法
11     * @param userData 一行数据对应的实体类对象
12     * @param context 读取上下文(包含sheet、行号等信息)
13     */
14    @Override
15    public void invoke(UserData userData, AnalysisContext context) {
16        log.info("读取到第{}行数据:{}", context.readRowHolder().getRowIndex(), userData);
17        // 2. 将数据加入集合
18        dataList.add(userData);
19    }
20
21    /**
22     * 所有数据读取完成后调用的方法
23     * 适合做最终处理(比如批量入库、数据汇总)
24     */
25    @Override
26    public void doAfterAllAnalysed(AnalysisContext context) {
27        log.info("Excel读取完成!共读取{}行有效数据", dataList.size());
28        System.out.println("dataList = " + dataList);
29        // 这里可以写后续逻辑:比如调用service批量保存到数据库
30        // userService.batchSave(dataList);
31    }
32
33    // 提供getter方法,方便外部获取读取到的数据
34    public List<UserData> getDataList() {
35        return dataList;
36    }
37}
38

EasyExcel的使用》 是转载文章,点击查看原文


相关推荐


提示词工程入门-03
一诺滚雪球2026/2/6

前言 "写个代码" "帮我写个快速排序函数,用 Python 实现,要求时间复杂度 O(n log n),添加详细注释" 同样是让 AI 写代码,为什么第一个指令得到的是模糊的回复,而第二个能得到精确满足需求的代码? 这就是提示词工程(Prompt Engineering)的魔力。 好的 Prompt = 好的输出。今天我们来学习如何写出让 AI "秒懂"的提示词。 1. 什么是提示词工程 提示词(Prompt):你给大模型的输入指令 提示词工程(Prompt Engineering):设计和


耗时 20 天,AI 漫剧 APP 和 Web 全部开源, 已斩获 764 星!
苍何2026/1/28

这是苍何的第 474 篇原创! 大家好,我是消失了一段时间的苍何。 1 月 5 号,我写了篇文章,并开源了 AI 漫剧 APP,获得了很多朋友的喜欢。 然后在 GitHub 上一共获得了 764 星和 181 fork,让我有些吃惊。 说实话,这个项目远超我们的预期,甚至连歪果哥都来给我们提 issue,希望支持双语。 甚至还有老板来咨询问我卖不卖这个 APP,我说,大哥,咱都开源了,自己去整吧,不用付费,哈哈哈。 这或许就是开源的魅力吧。 但我发现,APP 还是不大方便,评论区也不少求


万字长文!搞懂机器学习中的概率图模型
aicoting2026/1/19

推荐直接网站在线阅读:aicoting.cn 概率图模型(Probabilistic Graphical Models, PGM)是一类结合概率论与图论的强大工具,用于描述多个随机变量之间的依赖关系。它通过图结构将复杂的联合概率分布分解为局部条件概率分布,使得对高维数据建模和推断变得可行且高效。 根据图的类型,PGM 可分为有向图模型(如贝叶斯网络)和无向图模型(如马尔可夫随机场)。贝叶斯网络利用有向无环图表示变量之间的因果关系,适合建模因果推断和序列数据;马尔可夫随机场则通过无向图捕捉变量之


WPF样式进阶实战:外置样式+MVVM主题切换+样式优先级全解析
bugcome_com2026/1/11

在WPF开发中,样式(Style)是实现界面美化、统一风格、提高代码复用性的核心利器。但很多开发者在实际项目中,容易陷入「内联样式冗余」「主题切换困难」「样式优先级混乱」的困境,写出难以维护的XAML代码。 今天我们就通过一个完整的模块化实战项目(附全部可运行代码),从「外置样式封装」到「MVVM模式主题切换」,再到「样式优先级核心知识点」,全方位解锁WPF样式的高级用法,最终实现一个支持「浅/深色全局主题切换」「按钮专属样式切换」「传统后台代码样式切换」的完整案例。 一、项目架构梳理:模块化让


2025年终总结,智启
袁庭新2026/1/3

大家好,我是袁庭新。2025年就这么溜走了,对我而言,是极为不寻常的一年,总是想着用文字把它记录下来。 文章输出 写是为了更好的思考,坚持写作,力争更好的思考。 2025年累计发表54篇原创文章,平均1周更1篇,大多数是技术相关。2025年我有个转变——每个月写一篇月总结,对这个月主要做了什么事做一个系统的梳理,尽量以可量化的形式呈现,比如,这个月写了多少篇文章,拍了几条短视频,录了几节课,办了几场讲座等诸如此类。 为什么采用这种方式呢?前些年我也不是没写过年终总结,年底一回顾,感觉又稀里糊涂过


一文带你吃透 Java 反射机制
BestAns2025/12/24

一文带你吃透 Java 反射机制 在Java开发中,“反射”绝对是个让人又爱又恨的知识点。有人觉得它晦涩难懂、破坏封装,也有人靠它实现了各种灵活的功能——比如框架开发、动态配置加载。 其实反射没那么神秘,今天就给大家用最通俗的语言讲清楚:反射到底是什么、怎么用,以及反射在实际开发中的应用。 一、Java反射到底是什么? 我们先从Java的核心特性“封装”说起。平时写代码时,我们通过new关键字创建对象,调用类的方法、访问属性,都是在“编译期”就确定好要操作的类,比如User user = new


为什么说 AI 赋能前端开发,已经不是选择题,而是必然趋势?
西陵2025/12/16

首发于公众号 code进化论,欢迎关注。 前言 这几年 AI 在前端开发里的能力几乎是肉眼可见地进化”。从最早只能帮我们做做代码补全、提示几个参数,例如早期的 comate。到后来能够独立生成一个完整的 React/Vue 组件,连逻辑、样式和交互都能自动写好,例如 cursor 和 claude。再到现在,AI 已经能根据一句自然语言去搭建整个前端项目,自动创建页面、路由、接口层,甚至跑通基础业务流程,例如 v0 和 bolt.new。AI 的角色正在从“聪明的编辑器”变成“能独立干活的虚拟工


计算机十万个为什么--数据库索引
无限大62025/12/8

计算机十万个为什么--数据库索引 大家好,欢迎来到最新一期的无限大博客。 突然发现自己对数据库相关的内容掌握不够扎实,于是就去学习了一下,顺便也将自己的理解写成了一篇博客。 希望这篇文章能对大家有所帮助 数据库索引:给数据仓库装个"智能导航系统" 🧭 想象一下,你走进一个占地 1000 平方米的超级图书馆 📚,里面塞满了几十万本书,却连个分类牌都没有。老板忽然喊你找一本《数据库从入门到放弃》,你是不是当场想表演一个原地消失术?😱 这就是没有索引的数据库的日常!每次查询都像蒙眼找书,全表


失业7个月,我把公司开起来了:一个程序媛的“野蛮生长”
后端小肥肠2025/11/28

大家好,我是小肥肠。 4月被裁,11月注册公司。 这7个月,我一个人赚回了以前一年的工资,也攒够了人生第一台CC的首付。今天不讲技术,聊聊这半年一个程序媛的野蛮生长。 1. 半年了我开起了公司 从4月到现在已经创业半年多了(7个月),这7个月以来,我从一个一无所有的失业人到现在攒够了一台cc的首付(赚的比以前上班一年还多),我的共学社群实现了从0到现在的300多人。 其中有很多和我一样的程序员,他们都是被我的文章吸引来共学群一起成长,也有很多小白进来一步一步成长为可以自行搭建自己的智能体。 在这


一个简单Demo彻底理解前后端怎么连的丨Figma + Supabase + Vercel
阿星AI工作室2026/2/23

哈喽,大家好! 我是阿星👋 很多小白编程学了三个月,全是AI做主UI,难以融入自己的设计理念。 甚至不了解前后端到底怎么连通的。 一旦代码出错了,可能和AI对话还要重新理解一遍概念。所以今天,我们通过一个简单的case,把一个完整前后端的核心链路全跑一遍👇🏻 让你能自己把控UI、把控数据库、把控前端、后端。 🗺️ 先看一眼全局流程 整件事分五步,每一步做完了才能进下一步: ① Figma 画页面 →  ② 定接口契约 →  ③ Supabase 建数据库→  ④ AI 帮你写连接代码

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客