-
2021-12-27 14:53:31
合并行:
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import lombok.Data; 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; /** * 合并单元格 */ @Data public class ExcelFillCellMergeStrategy implements CellWriteHandler { /** * 合并字段的下标 */ private int[] mergeColumnIndex; /** * 合并几行 */ private int mergeRowIndex; public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) { this.mergeRowIndex = mergeRowIndex; this.mergeColumnIndex = mergeColumnIndex; } @Override public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) { } @Override public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) { } public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) { } @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) { //当前行 int curRowIndex = cell.getRowIndex(); //当前列 int curColIndex = cell.getColumnIndex(); if (curRowIndex > mergeRowIndex) { for (int i = 0; i < mergeColumnIndex.length; i++) { if (curColIndex == mergeColumnIndex[i]) { mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex); break; } } } } 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); } } } }
合并列:
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; 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.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import java.util.List; /** * 自定义合并某行某列 */ public class ExcelFillCellMergePrevCol implements CellWriteHandler { /** * 合并字段的下标 */ private int[] mergeColumnIndex; //合并哪一行 private int row; //合并多少列 private int num; public ExcelFillCellMergePrevCol(int[] mergeColumnIndex, int row, int num) { this.mergeColumnIndex = mergeColumnIndex; this.row = row; this.num = num; } @Override public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) { } @Override public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) { } @Override public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) { } @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) { //当前行 int curRowIndex = cell.getRowIndex(); //当前列 int curColIndex = cell.getColumnIndex(); //合并最后一行指定列 if (curRowIndex == row) { for (int i = 0; i < mergeColumnIndex.length; i++) { if (curColIndex == mergeColumnIndex[i]) { // 合并最后一行 ,列 mergeWithPrevCol(writeSheetHolder, cell, curRowIndex, curColIndex); } } } } private void mergeWithPrevCol(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) { Sheet sheet = writeSheetHolder.getSheet(); CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex, curRowIndex, curColIndex, curColIndex + num); sheet.addMergedRegion(cellRangeAddress); } }
更多相关内容 -
easyexcel合并单元格
2022-02-11 09:45:49原文连接... -
easyExcel导出合并单元格策略
2021-12-21 17:12:32easyExcel导出合并单元格策略 WriteSheet writeSheet = EasyExcel.writerSheet(i, "Sheet" + (i + 1)) .registerWriteHandler(new CustomCellWriteHandler()) //设置合并单元格策略 .registerWriteHandler(new ... -
easyexcel 合并单元格
2020-07-25 21:15:07easyexcel合并单元格
easyexcel 合并单元格
*********************
相关注解
ContentLoopMerge:标注在字段上
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ContentLoopMerge { int eachRow() default -1; //合并行 int columnExtend() default 1; //合并列 }
OnceAbsoluteMerge:标注在类上
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface OnceAbsoluteMerge { int firstRowIndex() default -1; //初始行 int lastRowIndex() default -1; //最后一行 int firstColumnIndex() default -1; //初始列 int lastColumnIndex() default -1; //最后一列 }
*********************
示例
Test
@Data class Book{ @ContentLoopMerge(eachRow = 2) private Integer id; private String name; private Double price; } public class Test { private static final String write_path="e:"+ File.separator+"java"+File.separator+"easyexcel"+File.separator+"write.xlsx"; public static void write(){ List<Book> list=new ArrayList<>(); for (int i=0;i<5;i++){ Book book=new Book(); book.setId(i); book.setName("海贼王"+i); book.setPrice((double)(i+10)); list.add(book); } EasyExcel.write(write_path,Book.class).sheet().doWrite(list); } public static void main(String[] args){ write(); } }
****************
使用测试
-
easyexcel 合并单元格-表头
2021-02-01 09:04:181. 添加依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>...2.表头(含单元格合并) public List<1. 添加依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency>
2.表头(含单元格合并)
public List<List<String>> ExcelHead() { List<List<String>> headList = new ArrayList(); headList.add(new ArrayList() {{ add("时间"); add("参数名\\回路名"); }}); headList.add(new ArrayList() {{ add("时间" }}); headList.add(new ArrayList() {{ add("时间"); add("电流I(A)"); }}); headList.add(new ArrayList() {{ add("环境温度:" + temperature); add("相电压U"); }}); headList.add(new ArrayList() {{ add("环境温度"); add("线电压U"); }}); headList.add(new ArrayList() {{ add("环境温度"); add("频率(Hz)"); }}); headList.add(new ArrayList() {{ add("环境湿度"); add("开关分合(分\\合)"); }}); headList.add(new ArrayList() {{ add("环境湿度"); add("总有功功率(kW)"); }}); headList.add(new ArrayList() {{ add("抄表记录单"); add("总无功功率(kVar)"); }}); headList.add(new ArrayList() {{ add("抄表记录单"); add("总功率因数"); }}); headList.add(new ArrayList() {{ add("抄表记录单"); add("正向有功电能(kW.h)"); }}); headList.add(new ArrayList() {{ add("项目"); add("正向无功电能(kVar.h)"); }}); headList.add(new ArrayList() {{ add("表单号"); add("所属变压器"); }}); headList.add(new ArrayList() {{ add("表单号"); add("变压器温度(℃)"); }}); return headList; }
3. 数据逻辑
List<HashMap> data = statisticmapper.runreport(statisticdto); for (int i = 0; i < data.size(); i++) { String id = data.get(i).get("id").toString(); String name = data.get(i).get("equipment_name").toString(); if (data.get(i).get("paramid") == null) continue; String paramid = data.get(i).get("paramid").toString(); String point_id = data.get(i).get("point_id").toString(); String value = data.get(i).get("value").toString(); switch (paramid) { case "e2fa092c-6146-11eb-82f0-6c2b59bec1ff": temperature = value + "℃ "; continue; case "70536171-6147-11eb-82f0-6c2b59bec1ff": humidity = value + "%"; continue; } if (!devicecheck.contains(id)) { tosave.add(rowdata(name, "A相")); tosave.add(rowdata(name, "B相")); tosave.add(rowdata(name, "C相")); devicecheck.add(id); } if (dic.containsKey(id + point_id)) continue; dic.put(id + point_id, i); int index = devicecheck.indexOf(id) * 3; switch (paramid) { case "069d9c73-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(5, value); tosave.get(index + 1).set(5, value); tosave.get(index + 2).set(5, value); break; case "068d17d6-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(7, value); tosave.get(index + 1).set(7, value); tosave.get(index + 2).set(7, value); break; case "071ce9e3-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(8, value); tosave.get(index + 1).set(8, value); tosave.get(index + 2).set(8, value); break; case "05b23645-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(9, value); tosave.get(index + 1).set(9, value); tosave.get(index + 2).set(9, value); break; case "062ee255-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(10, value); tosave.get(index + 1).set(10, value); tosave.get(index + 2).set(10, value); break; case "06dd3edb-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(11, value); tosave.get(index + 1).set(11, value); tosave.get(index + 2).set(11, value); break; case "061fa440-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(2, value); break; case "06fa867e-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(3, value + "kV"); break; case "05952cc2-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index).set(4, "Uab(" + value + "kV)"); break; case "06805737-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index + 1).set(2, value); break; case "05f1ca1b-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index + 1).set(3, value + "kV"); break; case "06ab9dbf-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index + 1).set(4, "Uab(" + value + "kV)"); break; case "0604e966-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index + 2).set(2, value); break; case "058946a7-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index + 2).set(3, value + "kV"); break; case "06b858c6-6148-11eb-82f0-6c2b59bec1ff": tosave.get(index + 2).set(4, "Uab(" + value + "kV)"); break; } }
public List<String> rowdata(String name, String type) { return new ArrayList() {{ add(name); add(type); add("-"); add("-"); add("-"); add("-"); add("-"); add("-"); add("-"); add("-"); add("-"); add("-"); add("无"); add("-"); }}; }
3.excel
List<List<String>> head = ExcelHead(); EasyExcel.write(fileUrl).head(head).sheet(sheetname) // .registerWriteHandler(StyleStrategy()) // .registerWriteHandler(new ReportMergeStrategy(devicecheck.size()))//自定义合并 单元格 // .registerWriteHandler(new RowWriteHandler()) .doWrite(tosave);
4. 结果
时间 环境温度 环境湿度 抄表记录单 项目 表单号 参数名\回路名 电流I(A) 相电压U 线电压U 频率(Hz) 开关分合(分\合) 总有功功率(kW) 总无功功率(kVar) 总功率因数 正向有功电能(kW.h) 正向无功电能(kVar.h) 所属变压器 变压器温度(℃) 1#高压出线 A相 0.00 10.54kV Uab(10.54kV) 50.00 - 0.00 - 0.00 - - 无 - 1#高压出线 B相 0.00 10.52kV Uab(10.50kV) 50.00 - 0.00 - 0.00 - - 无 - 1#高压出线 C相 0.00 10.50kV Uab(10.52kV) 50.00 - 0.00 - 0.00 - - 无 - -
EasyExcel合并单元格(一)
2021-02-01 01:21:09前言 导出excel,这里介绍每隔2行... * 合并单元格 * @date 01/31/2021 03:11 */ public class Demo { /** * 合并单元格 */ @Test public void testMyMergeWrite() { // String fileName = TestFileUtil.getPat前言
导出excel,介绍如何使用LoopMergeStrategy实现简单的合并
效果
每隔2行,合并一次
横向合并
横向和纵向合并
实现
导入依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.7</version> </dependency> <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1-jre</version> </dependency> <!-- springboot test启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
单元测试
/** * 合并单元格 * @date 01/31/2021 03:11 */ public class Demo { /** * 合并单元格 */ @Test public void testMyMergeWrite() { String fileName = "/Users/quanlinglong/Downloads/mergeDemo/" + "mymergeWrite" + System.currentTimeMillis() + ".xlsx"; System.out.println("fileName = " + fileName); // 每隔2行合并一次,横向合并1列,从第0列开始 // LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 1, 0); // 上面的等价于 // LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); // 从第columnIndex列开始,向右合并(columnExtend-1)列 // LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(1, 2, 0); // 合并2行2列 LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 2, 0); EasyExcel.write(fileName, WriteDemo.DemoData.class) .registerWriteHandler(loopMergeStrategy) .sheet("aaa") .doWrite(data()); } private List<List<Object>> data() { List<List<Object>> result = new ArrayList<>(); for (int i = 0; i < 3; i++) { result.add(Lists.newArrayList("标题" + i, new Date(), i * 0.1)); } return result; } }
分析LoopMergeStrategy类,它继承AbstractRowWriteHandler,在afterRowDispose方法里对每行做了处理,LoopMergeStrategy的构造函数传参是用来设置合并范围CellRangeAddress,再添加到当前sheet。
public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { if (!isHead) { if (relativeRowIndex % this.eachRow == 0) { CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum(), row.getRowNum() + this.eachRow - 1, this.columnIndex, this.columnIndex + this.columnExtend - 1); writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress); } } }
CellRangeAddress构造函数有4个参数
参数
0:合并起始行
1:合并终止行
2:合并起始列
3:合并终止列CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum(), row.getRowNum() + this.eachRow - 1, this.columnIndex, this.columnIndex + this.columnExtend - 1); writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
构造函数传进来的eachRow, columnExtend, columnIndex,都用在这里了
相关链接
easyexcel 动态合并单元格 -
easyexcel 合并单元格(非注解)
2020-09-16 14:02:27--引入 阿里的 easyexcel 同时需要引入 asm 或者 cglib--> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.4</... -
利用easyExcel导出上万条数据,自定义策略合并单元格
2020-12-04 12:45:30easyExcel 2.1.7 poi 3.17 springboot 2.2.5 lombok 1.18.12 -
关于使用EasyExcel进行单元格合并的问题
2022-05-09 10:33:41关于使用EasyExcel进行单元格合并的问题 1.项目场景: 简介:报销单导出要根据指定的excel模板去自动替换对应,然后重新生成一份新的excel。在给定的excel模板中,有部分字段进行了单元格合并,如下所示。 2.问题... -
导出自动合并单元格.java
2020-06-17 11:19:35支持大数据量导出excel。自动合并相同数据单元格,可根据id自动识别是否合并,支持自定义类型数据转换,根据实体类自动识别。 -
easyExcel中合并单元格文件读取实现方案
2022-05-18 00:19:20表格中8行数据,就是进行了八次读取,对于合并单元格所在的列,只有第一行进行了数据映射,其余均为null,所以从这里从每行读取完成之后进行数据组装即可。 读取测试类: public class PersonalExcel { public ... -
easyexcel读取合并单元格
2020-12-01 18:01:43文章目录easy-excel读取合并单元格一、设置读取额外信息二、重写Listener中的extra()方法,获取合并单元格的信息三、遍历合并单元格的信息四、代码清单1. UploadDataListener.java2. ExcelAnalysisHelper.java 一、... -
EasyExcel导出合并单元格
2021-03-01 15:09:30//需要做合并单元格,对应的列数 int[] mergeColumeIndex = {0,1,2,3,4,5,6,7,8,9,10,11}; 以上可多可少 , 看自己实际需要 。 然后就是, EasyExcel.write(response.getOutputStream(), 导出.class) -
EasyExcel 单元格合并
2022-02-23 09:09:14countryCount 合并行数集合。 如下图 list则为6,5。同理productTypeCount import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.merge.AbstractMergeStrategy; import org.apache.poi.ss.... -
easyexcel 动态合并单元格
2020-12-01 14:54:08easyexcel 动态合并单元格 目前操作excel文档的底层都是用poi来进行的,在早期工作开发过程中,是基于poi,然后对每一个数据单元格进行操作代码编写,后面有一些比较好的开源项目,像easyexcel、easypoi、hutool等,... -
EasyExcel合并单元格策略样例
2022-06-24 14:54:48自定义EasyExcel单元格合并策略,动态合并单元格。 -
EasyExcel自定义合并单元格导出
2021-07-27 15:56:59根据业务需求会有导出中需要合并的功能,但是当根据数据合并时又不能使用注解来进行合并,只能自定义合并,根据官网中介绍可以使用第二种方式,官网地址https://www.yuque.com/easyexcel/doc/write#cac25459 ... -
EasyExcel导出自定义合并单元格的策略
2022-02-11 10:19:29目前网上找到的EasyExcel自定义合并单元格都是ExcelFillCellMergeStrategy,这个工具类只要下一行的cell和上一行的cell内容相同就会合并,不符合目前的需求。本例也是在此基础上进行逻辑修改。 参考链接。 测试代码 ... -
EasyExcel合并相同内容单元格及动态标题功能的实现
2022-06-22 10:57:56相信很多同学都用过EasyExcel做过导出功能,现在阿Q也碰到一个需求,就是要把导出的Excel中内容相同的纵向单元格给合并,然后还需要给Excel设置动态标题,再进行格式定义调整,现将这个功能的实现过程记录下,给同学... -
EasyExcel导入存在合并单元格的Excel
2021-08-09 19:50:56因为POI/EasyExcel对合并单元格的数据只读取一次,需要把为空的单元格也赋值,这是核心技术难点。 对数据进行校验、封装然后写入数据库 存在校验不通过的数据返回给前端,所有数据校验通过写入数据库。 相关代码 ... -
easyexcel 导出导入合并单元格的表格
2021-09-29 18:04:58easyexcel 导入、导出合并单元格的表格 现在经常遇到导入导出表格,又有列重复的数据,想要合并,手动有太慢的(所以直接导入或导入和并的表格) 1. 引入pom 引入pom 参考 java导入Excel(使用阿里巴巴的easyexcel... -
java-easyExcel导出-合并单元格
2021-12-13 10:59:15/** * 合并单元格 */ @Data public class ExcelFillCellMergeStrategy implements CellWriteHandler { /** * 合并字段的下标 */ private int[] mergeColumnIndex; /** * 合并几行 */ private int mergeRowIndex; ... -
poi导入/导出Excel表格,合并单元格的读取和设置
2017-03-25 14:25:49poi导入/导出Excel表格,合并单元格的读取和设置 -
EasyExcel 实现批量合并单元格(支持自定义)
2021-04-24 10:33:571 Maven配置文件 2 MergeCellModel 3 CustomMergeCellHandler 4 调试代码 5 调试结果 注: 1 Maven配置文件 cn.hutool hutool-all 5.5.1 com.alibaba easyexcel 2.2.8 2 MergeCellModel 合并单元格信息... -
EasyExcel填充时合并单元格
2021-01-20 17:03:41由于填充时第二行开始,easyexcel不会自动合并单元格,所以需要自定义handler根据上一行的合并信息自行合并 public class MyHandler extends AbstractMergeStrategy { @Override protected void merge(Sheet ...
收藏数
1,047
精华内容
418