【JAVA开发笔记】实战演练,如何用EasyExcel导出表格,并且自定义合并单元格

目录

1. 前言

2. EasyExcel简介

3. EasyExcel简单导出案例讲解

3.1 EasyExcel依赖引入

3.2 测试类创建

3.3 Excel导出实现

4. EasyExcel合并单元案例讲解

4.1 实现自定义合并策略

4.2 使用自定义合并策略

5. 总结


1. 前言

项目上,需将一个列表数据导出Excel表格,并将指定列相同数据自动合并单元格,琢磨学习了下easyexcel实现效果如下:

如上图所示,指定A、B两列相同行自动合并。

2. EasyExcel简介

  • EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。
  • EasyExcel相比其他Excel解析框架(Apache poi和jxl),拥有更好的内存消耗管理算法。特别是对07版Excel的解决,EasyExcel重写了底层解析逻辑,一个3M的Excel解析只需要几M内存,但是用poi解析可能需要100M左右的内存。EasyExcel提高了读取性能,64M内存20秒读取75M的Excel,还有更快的极速模式,但是消耗的内存会更多一些。
  • EasyExcel支持自定义策略合并单元格,可以方便快捷填充数据到模板中,有活跃的中文社区支持,完善的测试用例可以覆盖大部分业务场景的使用。

3. EasyExcel简单导出案例讲解

 本章节实现效果如下:

3.1 EasyExcel依赖引入

注意文中还需引入Lombok注解

        <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version></dependency>

3.2 测试类创建

@ContentRowHeight(50) //内容行高

@HeadRowHeight(15) //表头行高

@ColumnWidth(20) //列宽度

@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER) // 内容样式,本处设置是水平和垂直居中

@ExcelProperty("国家/地区") //表头信息

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import com.alibaba.excel.enums.poi.VerticalAlignmentEnum;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;/*** @Author: lxy* @CreateTime: 2024-06-11* @Description: 测试类*/
@Getter
@Setter
@Builder
@EqualsAndHashCode
@HeadRowHeight(50) // 表头行高
@ContentRowHeight(15) // 内容行高
@ColumnWidth(20) // 列宽度
public class TestEntity {@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER) // 内容样式@ExcelProperty("国家/地区")private String row1;@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER) // 内容样式@ExcelProperty("省份/州/自治区/特别行政区")private String row2;@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER) // 内容样式@ExcelProperty("城市/县/市辖区")private String row3;
}

3.3 Excel导出实现

使用EasyExcel导出简单Excel代码示例如下:

    @Testpublic void simplyWriteExcel() {// 数据就初始化List<TestEntity> resultList = new ArrayList<>();resultList.add(TestEntity.builder().row1("中国").row2("广东省").row3("深圳市").build());resultList.add(TestEntity.builder().row1("中国").row2("广东省").row3("广州市").build());resultList.add(TestEntity.builder().row1("中国").row2("新疆维吾尔自治区").row3("乌鲁木齐市").build());resultList.add(TestEntity.builder().row1("中国").row2("新疆维吾尔自治区").row3("喀什地区").build());resultList.add(TestEntity.builder().row1("中国").row2("香港特别行政区").row3("香港岛").build());resultList.add(TestEntity.builder().row1("中国").row2("香港特别行政区").row3("九龙半岛").build());resultList.add(TestEntity.builder().row1("美国").row2("加利福尼亚州").row3("洛杉矶市").build());resultList.add(TestEntity.builder().row1("美国").row2("加利福尼亚州").row3("旧金山县").build());resultList.add(TestEntity.builder().row1("美国").row2("德克萨斯州").row3("休斯敦市").build());resultList.add(TestEntity.builder().row1("美国").row2("德克萨斯州").row3("达拉斯县").build());resultList.add(TestEntity.builder().row1("美国").row2("纽约州").row3("纽约市").build());resultList.add(TestEntity.builder().row1("美国").row2("纽约州").row3("布法罗县").build());// 设置文件名称String fileName = "C:\\Users\\Lixy\\Desktop\\test01.xlsx";// 1、指定写出文件名称以及用哪个class去写// 2、设置文件流自动关闭// 3、输出写出Excel的sheet名称(自定义)// 4、指定写出的数据EasyExcel.write(fileName, TestEntity.class).autoCloseStream(Boolean.TRUE).sheet("Sheet1").doWrite(resultList);}

4. EasyExcel合并单元案例讲解

注:EasyExcel依赖和测试类,与章节3保持一致,本章节不再做讲解

 本章节实现效果如下:

4.1 实现自定义合并策略

CellWriteHandler 是 EasyExcel 中的一个接口,它允许开发者在写入单元格时执行自定义逻辑,如设置单元格样式、合并单元格等。

下面是一个的 CellWriteHandler 示例,实现了如何判断上下行数据相同,并对数据进行合并单元格:

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.List;/*** @Author: lxy* @CreateTime: 2024-06-12* @Description: EasyExcel单元格合并处理器*/
public class ExcelMergeHandler implements CellWriteHandler {private int[] mergeColumnIndex;private int mergeRowIndex;public ExcelMergeHandler() {}/*** 构造函数** @param mergeRowIndex     合并开始的行索引* @param mergeColumnIndex  要合并的列索引数组*/public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {this.mergeRowIndex = mergeRowIndex;this.mergeColumnIndex = mergeColumnIndex;}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 当前行索引int curRowIndex = cell.getRowIndex();// 当前列索引int curColIndex = cell.getColumnIndex();// 如果当前行大于合并开始行if (curRowIndex > mergeRowIndex) {// 当前列在需要合并的列中for (int columnIndex : mergeColumnIndex) {if (curColIndex == columnIndex) {// 进行合并操作mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);break;}}}}/*** 当前单元格向上合并** @param writeSheetHolder 当前工作表持有者* @param cell             当前单元格* @param curRowIndex      当前行索引* @param curColIndex      当前列索引*/private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {// 获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();// 获取前一个单元格的数据Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();// 判断当前单元格和前一个单元格的数据以及主键是否相同if (curData.equals(preData)) {// 获取工作表Sheet sheet = writeSheetHolder.getSheet();// 获取已合并的区域List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();boolean isMerged = false;// 检查前一个单元格是否已经被合并for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {CellRangeAddress cellRangeAddr = mergeRegions.get(i);// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {sheet.removeMergedRegion(i);cellRangeAddr.setLastRow(curRowIndex);sheet.addMergedRegion(cellRangeAddr);isMerged = true;}}// 如果前一个单元格未被合并,则新增合并区域if (!isMerged) {CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);sheet.addMergedRegion(cellRangeAddress);}}}@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {}@Overridepublic void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {}
}

4.2 使用自定义合并策略

要使用 CellWriteHandler,通常需要实现其定义的方法,并在创建 ExcelWriter 时通过 registerWriteHandler 方法将其注册到 EasyExcel 的上下文中,这样,当 EasyExcel 写入单元格时,就会调用这些自定义的处理器方法。

在创建 ExcelWriter 并写入数据时,可以如下注册这个处理器:

    @Testpublic void writeExcel() {// 需要合并的列int[] mergeColumnIndex = {0,1};// 需要从第几行开始合并int mergeRowIndex = 1;// 数据就初始化List<TestEntity> resultList = new ArrayList<>();resultList.add(TestEntity.builder().row1("中国").row2("广东省").row3("深圳市").build());resultList.add(TestEntity.builder().row1("中国").row2("广东省").row3("广州市").build());resultList.add(TestEntity.builder().row1("中国").row2("新疆维吾尔自治区").row3("乌鲁木齐市").build());resultList.add(TestEntity.builder().row1("中国").row2("新疆维吾尔自治区").row3("喀什地区").build());resultList.add(TestEntity.builder().row1("中国").row2("香港特别行政区").row3("香港岛").build());resultList.add(TestEntity.builder().row1("中国").row2("香港特别行政区").row3("九龙半岛").build());resultList.add(TestEntity.builder().row1("美国").row2("加利福尼亚州").row3("洛杉矶市").build());resultList.add(TestEntity.builder().row1("美国").row2("加利福尼亚州").row3("旧金山县").build());resultList.add(TestEntity.builder().row1("美国").row2("德克萨斯州").row3("休斯敦市").build());resultList.add(TestEntity.builder().row1("美国").row2("德克萨斯州").row3("达拉斯县").build());resultList.add(TestEntity.builder().row1("美国").row2("纽约州").row3("纽约市").build());resultList.add(TestEntity.builder().row1("美国").row2("纽约州").row3("布法罗县").build());// 设置文件名称String fileName = "C:\\Users\\Lixy\\Desktop\\test02.xlsx";// 1、指定写出文件名称以及用哪个class去写// 2、设置文件流自动关闭// 3、设置自定义的写入处理逻辑,注册ExcelMergeHandler示例// 4、输出写出Excel的sheet名称(自定义)// 5、指定写出的数据EasyExcel.write(fileName, TestEntity.class).autoCloseStream(Boolean.TRUE).registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeColumnIndex)).sheet("Sheet1").doWrite(resultList);}

5. 总结

EasyExcel功能灵活强大,可以根据自身业务场景去自定义样式,也可以使用通过模板填充功能实现导出国际化语言等复杂功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/353136.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简易开发一个app

即时设计网站 即时设计 - 可实时协作的专业 UI 设计工具 需要先设计好UI界面 上传到codefun 首次需要安装 自动生成代码 打开hb软件 新建项目 打开创建的项目 删除代码 复制代码过去 下载图片 将图片放到文件夹里 改为这种格式 index.vue 如果不需要uni-app导航栏可以修改 …

ECharts 词云图案例二:创意蒙版应用

ECharts 词云图案例二&#xff1a;创意蒙版应用 引言 在数据可视化领域&#xff0c;ECharts 以其强大的功能性和灵活性&#xff0c;成为开发者和设计师的首选工具之一。继上一篇关于 ECharts 词云图的详细介绍后&#xff0c;本文将探索词云图的进阶应用——使用蒙版来创造更具…

生产看板管理系统内容有哪些?

相信很多做生产管理的朋友都会遇到如下问题&#xff0c;我就在想&#xff0c;是否能一个创建“透明的”的工作场所&#xff1f;让员工和管理者能够实时查询生产进度&#xff0c;及时发现生产中的问题。 生产进度难追踪 生产过程不透明 生产决策缺乏数据支持 ——能&#xf…

Blurry - hackthebox

简介 靶机名称&#xff1a;Blurry 难度&#xff1a;中等 靶场地址&#xff1a;https://app.hackthebox.com/machines/605 本地环境 靶机IP &#xff1a;10.10.11.19 linux渗透机IP(kali 2024.2)&#xff1a;10.10.16.17 windows渗透机IP&#xff08;windows11&#xff0…

虚拟机怎么额外搭建两个Redis节点,配置多个 Redis 实例

前提条件 在开始之前&#xff0c;请确保你已经具备以下条件&#xff1a; 一台已安装 Redis 的虚拟机。虚拟机上已安装基本的 Linux 工具&#xff08;例如 FinalShell&#xff09;。 步骤二&#xff1a;配置额外的 Redis 实例 接下来&#xff0c;我们将配置两个新的 Redis 实…

frp安装与配置

个人从网上杂乱的信息中学习、试错&#xff0c;记录自己成功配置的方法&#xff0c;避免遗忘 一、frp的下载 因目前无法下载&#xff0c;仅保留下载方法&#xff0c;版本号根据实际修改&#xff0c;目前使用0.54版&#xff0c;不同系统下载不同文件。 wget https://github.c…

【前端取不到cookie的的原因】http-only

某条cookie有http-only属性时&#xff0c;下面两种方法都取不到&#xff0c;还是改需求吧&#xff0c;别取了 1、 npm install js-cookie --save import Cookies from js-cookie let cookieValue Cookies.get(name)2、document.cookie

ChatGPT的问题与回复的内容导出(Chorme)

我给出两种方式&#xff0c;第一种方式无使用要求&#xff0c;第二种方式必须安装Chorme 个人更推荐第二种方式 第一种方式&#xff1a;使用chatgpt自带的数据导出 缺点&#xff1a;会将当前未归档的所有聊天记录导出&#xff0c;发送到你的电子邮箱中 第二种方式&#xff1a…

大模型技术工程师:抓住时代机遇,成为行业精英_

伴随AI大模型的火热&#xff0c;中国科技大厂们正在掀起一场「跑步AI化」的风暴。从顶层战略到业务线重构&#xff0c;AI无疑已成为大厂们押注未来的新故事。 大模型时代已经到来 大模型已成为全球竞争热点&#xff0c;一个大模型时代已经到来。 大模型具备三个特点&#xf…

智能网站管理系统

智能网站管理系统&#xff0c;即智能化的网站管理工具&#xff0c;是为了提高网站管理效率和简化操作流程而开发的一种软件系统。它集合了各种先进的技术和功能&#xff0c;为网站管理员提供了一套强大而可靠的解决方案。 智能网站管理系统的核心功能是网站内容管理。传统的网站…

css设置滚动条样式;滚动条设置透明

滚动条透明代码 .resizable-div {resize: both;/* 允许水平和垂直调整大小 */overflow: auto;/* 确保内容超出边界时出现滚动条 */ } /* 滚动条整体样式 */ .resizable-div::-webkit-scrollbar {width: 4px; /* 竖直滚动条宽度 */height: 4px; /* 水平滚动条高度 */ }/* 滚动条…

探索C嘎嘎的奇妙世界:第十四关---STL(string的模拟实现)

1. string类的模拟实现 1.1 经典的string类问题 上一关已经对string类进行了简单的介绍&#xff0c;大家只要能够正常使用即可。在面试中&#xff0c;面试官总喜欢让学生自己来模拟实现string类&#xff0c;最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数…

深度学习(九)——神经网络:最大池化的作用

一、 torch.nn中Pool layers的介绍 官网链接&#xff1a; https://pytorch.org/docs/stable/nn.html#pooling-layers 1. nn.MaxPool2d介绍 nn.MaxPool2d是在进行图像处理时&#xff0c;Pool layers最常用的函数 官方文档&#xff1a;MaxPool2d — PyTorch 2.0 documentation &…

11.docker镜像分层dockerfile优化

docker镜像的分层&#xff08;kvm 链接克隆&#xff0c;写时复制的特性&#xff09; 镜像分层的好处&#xff1a;复用,节省磁盘空间&#xff0c;相同的内容只需加载一份到内存。 修改dockerfile之后&#xff0c;再次构建速度快 分层&#xff1a;就是在原有的基础镜像上新增了服…

Thinkphp校园新闻发布系统源码 毕业设计项目实例

Thinkphp校园新闻发布系统源码 毕业设计项目实例 校园新闻发布系统模块&#xff1a; 用户模块&#xff1a;注册&#xff0c;登陆&#xff0c;查看个人信息&#xff0c;修改个人信息&#xff0c;站内搜索&#xff0c;新闻浏览等功能&#xff0c; 后台管理员模块&#xff1a;会员…

翻转数位00

题目链接 翻转数位 题目描述 注意点 可以将一个数位从0变为1找出能够获得的最长的一串1的长度&#xff08;必须是连续的&#xff09; 解答思路 参照题解使用动态规划解决本题&#xff0c;对于任意一个位置i&#xff0c;dp[i][0]表示到达且包含第i位不翻转0最长1的长度&…

每天一个数据分析题(三百五十九)- 多维分析模型

图中是某公司记录销售情况相关的表建立好的多维分析模型&#xff0c;请根据模型回答以下问题&#xff1a; 2&#xff09;产品表左连接品牌表的对应关系属于&#xff1f; A. 一对多 B. 一对一 C. 多对一 D. 多对多 数据分析认证考试介绍&#xff1a;点击进入 题目来源于CD…

等待 chrome.storage.local.get() 完成

chrome.storage.local.get() 获取存储处理并计数&#xff0c;内部计数正常&#xff0c;外部使用始终为0&#xff0c;百思不得其解。 如何在继续执行之前等待异步chrome.storage.local.get()完成-腾讯云开发者社区-腾讯云 (tencent.com) 原来我忽略了异步问题&#xff0c;最简…

推荐常用的三款源代码防泄密软件

三款源代码防泄密软件——安秉源代码加密、Virbox Protector 和 MapoLicensor——确实各自在源代码保护的不同方面有其专长。这些软件可以满足企业对于源代码保护的三大需求&#xff1a;防止泄露、防止反编译和防止破解。 安秉源代码加密&#xff1a; 专注于源代码文件的加密&…

【每天学会一个渗透测试工具】Nessus安装及使用指南

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 其他扫描工具&#xff1a; AWVS和Xray&#xff1a;应用漏洞扫描工具 fscan&#xff1a;虽然能扫主机&#xff0c;但比较老了…