EasyExcel-合并单元格
pom版本
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>
1.自定义合并单元格
在某些业务场景中可能会有合并单元格的需求,下面具体来说明如何实现
1.1 不合并单元格
先来看下不合并单元格的代码写法,简单复习下
public static void writeExcel() {
// 写excel的路径,当前项目路径下
String fileName = getPath();
// 构建ExcelWriter
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
// 构建sheet
WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class).build();
// 写sheet
excelWriter.write(data1(), writeSheet);
excelWriter.finish();
}
private static String getPath() {
return System.getProperty("user.dir") + "/" + System.currentTimeMillis() + ".xlsx";
}
private static List<DemoData> data1() {
List<DemoData> list = Lists.newArrayList();
for (int i = 0; i < 3; i++) {
DemoData data = new DemoData();
data.setString("字符串" + 1);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
for (int i = 0; i < 3; i++) {
DemoData data = new DemoData();
data.setString("字符串" + 2);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
for (int i = 0; i < 4; i++) {
DemoData data = new DemoData();
data.setString("字符串" + 3);
data.setDate(new Date());
data.setDoubleData(0.57);
list.add(data);
}
return list;
}
public static void main(String[] args) {
writeExcel();
}
打开输出的excel文件后如下,可以看到单元格没有合并。现在打算将第一列字符串标题相同的合并

1.2 合并单元格
// 自定义合并策略 该类继承了AbstractMergeStrategy抽象合并策略,需要重写merge()方法
public static class CustomMergeStrategy extends AbstractMergeStrategy {
/**
* 分组,每几行合并一次
*/
private List<Integer> exportFieldGroupCountList;
/**
* 目标合并列index
*/
private Integer targetColumnIndex;
// 需要开始合并单元格的首行index
private Integer rowIndex;
// exportDataList为待合并目标列的值
public CustomMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {
this.exportFieldGroupCountList = getGroupCountList(exportDataList);
this.targetColumnIndex = targetColumnIndex;
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
if (null == rowIndex) {
rowIndex = cell.getRowIndex();
}
// 仅从首行以及目标列的单元格开始合并,忽略其他
if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {
mergeGroupColumn(sheet);
}
}
private void mergeGroupColumn(Sheet sheet) {
int rowCount = rowIndex;
for (Integer count : exportFieldGroupCountList) {
if(count == 1) {
rowCount += count;
continue ;
}
// 合并单元格
CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
sheet.addMergedRegionUnsafe(cellRangeAddress);
rowCount += count;
}
}
// 该方法将目标列根据值是否相同连续可合并,存储可合并的行数
private List<Integer> getGroupCountList(List<String> exportDataList){
if (CollectionUtils.isEmpty(exportDataList)) {
return new ArrayList<>();
}
List<Integer> groupCountList = new ArrayList<>();
int count = 1;
for (int i = 1; i < exportDataList.size(); i++) {
if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
count++;
} else {
groupCountList.add(count);
count = 1;
}
}
// 处理完最后一条后
groupCountList.add(count);
return groupCountList;
}
}
// 修改WriteSheet的代码如下
public static void writeExcel() {
String fileName = getPath();
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
List<DemoData> demoDataList = data1();
// 写sheet的时候注册相应的自定义合并单元格策略
WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
.build();
excelWriter.write(demoDataList, writeSheet);
excelWriter.finish();
}
打开输出的excel文件后如下,可以看到第一列有相同值的单元格已经合并了,成功实现

同理若要合并第三列的数据,则可以在注册一个sheet写处理器,代码如下
public static void writeExcel() {
String fileName = getPath();
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
List<DemoData> demoDataList = data1();
WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
.build();
excelWriter.write(demoDataList, writeSheet);
excelWriter.finish();
}
excel打开如下:

1.3 写多个sheet
public static void writeExcel() {
String fileName = getPath();
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
List<DemoData> demoDataList = data1();
WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
.build();
excelWriter.write(demoDataList, writeSheet);
WriteSheet writeSheet1 = EasyExcel.writerSheet("模板2").head(DemoData.class).build();
excelWriter.write(data1(), writeSheet1);
excelWriter.finish();
}
输出excel可以看到已经有两个sheet了

1.4 WriteTable
若业务需求要求在同一个sheet中写多个表,就需要用到WriteTable了。只定义一个WriteSheet,有几个表就定义几个WriteTable
public static void writeExcel01() {
String fileName = getPath();
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build();
List<DemoData> demoDataList = data1();
// 需要表头设置为true,WriteTable一些属性会继承自WriteSheet
WriteTable writeTable = EasyExcel.writerTable(1).head(DemoData.class).needHead(Boolean.TRUE)
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
.build();
excelWriter.write(demoDataList, writeSheet, writeTable);
WriteTable writeTable1 = EasyExcel.writerTable(2).head(DemoData.class).needHead(Boolean.TRUE).build();
excelWriter.write(data1(), writeSheet, writeTable1);
excelWriter.finish();
}
打开excel表格如下

结语
如有错误或者优化点欢迎指出,本文参考自EasyExcel文档
EasyExcel-合并单元格的更多相关文章
- C# 获取Excel中的合并单元格
C# 获取Excel中的合并单元格 我们在制作表格时,有时经常需要合并及取消合并一些单元格.在取消合并单元格时需要逐个查找及取消,比较麻烦.这里分享一个简单的方法来识别Excel中的合并单元格,识别这 ...
- jquery操作表格 合并单元格
jquery操作table,合并单元格,合并相同的行 合并的方法 $("#tableid").mergeCell({ cols:[X,X] ///参数为要合并的列}) /** * ...
- NPOI操作EXCEL(五)——含合并单元格复杂表头的EXCEL解析
我们在第三篇文章中谈到了那些非常反人类的excel模板,博主为了养家糊口,也玩命做出了相应的解析方法... 我们先来看看第一类复杂表头: ...... 博主称这类excel模板为略复杂表头模板(蓝色部 ...
- poi获取合并单元格内的第一行第一列的值
当读取如图所示的excel时,显示为第1行 第1列 的内容是:合并单元格 其它在合并单元格区域内的单元格不显示 示例代码如下: import java.io.FileInputStream; impo ...
- Repeater多列分别合并单元格
GridView.Repeater合并单元格可以参考http://www.cnblogs.com/zhmore/archive/2009/04/22/1440979.html,但是原文例子是合并一列的 ...
- Aspose.Cells 首次使用,用到模版填充数据,合并单元格,换行
Aspose.Cells 首次使用,用到模版填充数据,合并单元格,换行 模版格式,图格式是最简单的格式,但实际效果不是这种,实际效果图如图2 图2 ,注意看红色部分,一对一是正常的,但是有一对多的订单 ...
- easyui datagrid 合并单元格
整理以前做的东西,这个合并单元格的问题再新浪博客也写过了..... 下面这段代码是列表数据 //载入排放系数管理报表数据 function LoadEmissionReportData() { //获 ...
- GRIDVIEW多行多列合并单元格(合并列)
GitHub项目地址:https://github.com/mingceng/merge-gridviewcell 去年的时候,我写了两篇文章: GridView多行多列合并单元格(完整代码和例子) ...
- C#导出Excel,并且设置Excel单元格格式,合并单元格.
注:要添加COM组件 Microsoft Excel 11.0 Object Library 引用. 具体代码如下: using System; using System.Collections.G ...
- 带复杂表头合并单元格的HtmlTable转换成DataTable并导出Excel
步骤: 一.前台JS取HtmlTable数据,根据设定的分隔符把数据拼接起来 <!--导出Excel--> <script type="text/javascript&qu ...
随机推荐
- Django实现统一包装接口返回值数据格式
前言 最近实在太忙了,开始了一个新的项目,为了快速形成产品,我选择了Django来实现后端,然后又拿起了之前我封装了项目脚手架「DjangoStarter」. 由于前段时间我写了不少.NetCore的 ...
- python---导入模块和包
导入模块和包 导入模块 import的过程中发生了哪些事情? 寻找模块 如果找到,开辟一块空间,执行这个模块 把这个模块中用到的名字都收录到开辟的空间中 创建一个变量来引用这个模块的空间 注意: 模块 ...
- FinClip 黑客马拉松正式开赛,码力集结,等你来战!
从2017到2022,小程序已经走过了5年的光景.从无人问津到互联网巨头纷纷入局,短短数年间,小程序已然发展成为超级 App 的标配!微信.支付宝.百度.抖音.今日头条--这些超级app的背后都有巨量 ...
- 帝国CMS灵动标签调用包含指定短语关键词关键字文章的语法
[e:loop={"select * from phome_ecms_news where title like '%这里是关键词%' and checked=1 order by news ...
- 【FAQ】应用集成HMS Core部分服务出现“ 6003报错”情况的解决方法来啦
背景 开发者在应用中集成HMS Core部分服务时,android sdk 以及flutter等跨平台sdk,会出现编译打包后,运行报6003错误码的情况.根据查询可以得知,错误代码 6003 表示证 ...
- C#面向抽象编程第二讲
抽象编程怎么说呢,以观察者模式为例: 观察者模式有两个对象,一个是观察者,一个是可观察者(字面翻译很别扭observable),消息发布者(提供者). 第一层如下,三个对象A.B.C分别有一个接收消息 ...
- 2021.11.03 P6175 无向图的最小环问题
2021.11.03 P6175 无向图的最小环问题 P6175 无向图的最小环问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 给定一张无向图,求图中一个至少包含 33 ...
- SpringBoot扩展点EnvironmentPostProcessor
一.背景 之前项目中用到了Apollo配置中心,对接Apollo配置中心后,配置中心的属性就可以在程序中使用了,那么这个是怎么实现的呢?配置中心的属性又是何时加载到程序中的呢?那么我们如果找到了这个是 ...
- 数据库-mysql索引篇
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. mysql的索引类型? mysql中有5种索引:普通索引.唯一索引.主键 ...
- 技术管理进阶——一线Leader与大Leader的差异是什么?
原创不易,求分享.求一键三连 前几年,因为下属的一些骚操作,Leader对我产生了误会,这导致了一些"不信任",这种不信任在短时间会让人丧失安全感,很多人会因此患得患失. 这种 ...