功能展示

功能类似这样:

开题序言

当时网上的资料大部分都是上下行相同的数据合并,唯独没有左右列的单元格合并。因此找资料花了一点时间,但功夫不负有心人,终于看到有两个和我要的功能差不多类似的文章。需要自取:

EasyExcel模板导出(行和列自动合并)_Lzfnemo2009的博客-CSDN博客_easyexcel模板导出

EasyExcel导出自定义合并单元格 策略 个人理解

写这篇文章只是为了自己以后参考。

以下进入正文:


1、导出的实体类,也就是表头

@Data
public class CityCapacityPo {@ExcelProperty(value = "时间",index = 0)private String time;@ExcelProperty(value = "出口",index = 1)private String export;@ExcelProperty(value = "地市",index = 2)private String direction;@ExcelProperty(value = "数据1",index = 3)private Double data1;@ExcelProperty(value = "数据2",index = 4)private Double data2;@ExcelProperty(value = "数据3",index = 5)private Double data3;@ExcelProperty(value = "数据4",index = 6)private Double data4;@ExcelProperty(value = "数据5",index = 7)private Double data5;@ExcelProperty(value = "数据6",index = 8)private Double data6;}

2、行合并工具类

public class ExcelFillCellMergeStrategyUtils implements CellWriteHandler {/*** 需要合并列的下标,从0开始*/private int[] mergeColumnIndex;/*** 从第几行开始合并,表头下标为0*/private int mergeRowIndex;public ExcelFillCellMergeStrategyUtils(int mergeRowIndex, int[] mergeColumnIndex) {this.mergeRowIndex = mergeRowIndex;this.mergeColumnIndex = mergeColumnIndex;}@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) {}@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {}@Overridepublic 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();Row preRow = cell.getSheet().getRow(curRowIndex - 1);if (preRow == null) {// 当获取不到上一行数据时,使用缓存sheet中数据preRow = writeSheetHolder.getCachedSheet().getRow(curRowIndex - 1);}Cell preCell=preRow.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);}}}}

3、列合并的工具类

@Data
@AllArgsConstructor
public class CellLineRange {/*** 起始列*/private int firstCol;/*** 结束列*/private int lastCol;
}
public class ExcelFillCelMergeStrategy implements CellWriteHandler {//自定义合并单元格的列 如果想合并   第4列和第5例 、第6列和第7例: [CellLineRange(firstCol=3, lastCol=4), CellLineRange(firstCol=5, lastCol=6)]private List<CellLineRange> cellLineRangeList;//自定义合并单元格的开始的行  一般来说填表头行高0 表示从表头下每列开始合并 :如表头行高位为3则 int mergeRowIndex = 2  ;private int mergeRowIndex;public ExcelFillCelMergeStrategy(List<CellLineRange> cellLineRangeList, int mergeRowIndex) {this.cellLineRangeList=cellLineRangeList;this.mergeRowIndex=mergeRowIndex;}@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) {}@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {}@Overridepublic 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) {if (curRowIndex > mergeRowIndex) {for (int i = 0; i < cellLineRangeList.size(); i++) {if (curColIndex > cellLineRangeList.get(i).getFirstCol()&&curColIndex<=cellLineRangeList.get(i).getLastCol()) {//单元格数据处理mergeWithLeftLine(writeSheetHolder, cell, curRowIndex, curColIndex);break;}}}}}/*** @description 当前单元格向左合并*/private void mergeWithLeftLine(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {//当前单元格中数据Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();//获取当前单元格的左面一个单元格Cell leftCell = cell.getSheet().getRow(curRowIndex).getCell(curColIndex - 1);//获取当前单元格的左面一个单元格中的数据Object leftData = leftCell.getCellTypeEnum() == CellType.STRING ? leftCell.getStringCellValue() : leftCell.getNumericCellValue();// 将当前单元格数据与左侧一个单元格数据比较if (leftData.equals(curData)) {//获取当前sheet页Sheet sheet = writeSheetHolder.getSheet();//得到所有的合并单元格List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();//是否合并boolean isMerged = false;for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {//CellRangeAddress POI合并单元格//CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol)//例子:CellRangeAddress(2, 6000, 3, 3);//第2行起 第6000行终止 第3列开始 第3列结束。CellRangeAddress cellRangeAddr = mergeRegions.get(i);// cellRangeAddr.isInRange(int rowInd, int colInd)确定给定坐标是否在此范围的范围内。// 若左侧一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元if (cellRangeAddr.isInRange(curRowIndex, curColIndex - 1)) {sheet.removeMergedRegion(i);cellRangeAddr.setLastColumn(curColIndex);sheet.addMergedRegion(cellRangeAddr);isMerged = true;}}// 若左侧一个单元格未被合并,则新增合并单元if (!isMerged) {CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex , curRowIndex, curColIndex- 1, curColIndex);sheet.addMergedRegion(cellRangeAddress);}}}}

4、调用工具类,开始合并:

@PostMapping("/exportCityOutletCapacityList")
@ApiOperation("导出Excel表")
public void exportCityOutletCapacityList(@RequestBody OutletCapacityParam param, HttpServletResponse response) {//获取需要导出的表数据List<CityCapacityPo> list=capacityFlowDao.selectCityOutletCapacityList(param);try {String fileName = "测试合并单元格";response.setContentType("application/octet-stream");response.setCharacterEncoding("utf-8");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");CityCapacityPo capacityPo=new CityCapacityPo();capacityPo.setExport("汇总");capacityPo.setTime("汇总");capacityPo.setDirection("汇总");//遍历列表,求各数据汇总capacityPo.setData1(list.stream().filter(Po-> Po.getData1()!=null).mapToDouble(CityCapacityPo::getData1).sum());capacityPo.setData2(list.stream().filter(Po-> Po.getData2()!=null).mapToDouble(CityCapacityPo::getData2).sum());capacityPo.setData3(list.stream().filter(Po-> Po.getData3()!=null).mapToDouble(CityCapacityPo::getData3).sum());capacityPo.setData4(list.stream().filter(Po-> Po.getData4()!=null).mapToDouble(CityCapacityPo::getData4).sum());capacityPo.setData5(list.stream().filter(Po-> Po.getData5()!=null).mapToDouble(CityCapacityPo::getData5).sum());capacityPo.setData6(list.stream().filter(Po-> Po.getData6()!=null).mapToDouble(CityCapacityPo::getData6).sum());list.add(capacityPo);ArrayList<CellLineRange> cellLineRanges=new ArrayList<>();//设置第几列开始合并int[] mergeColumnIndex = {0, 1};//设置第几行开始合并int mergeRowIndex = 1;cellLineRanges.add(new CellLineRange(0,2));EasyExcel.write(response.getOutputStream())              //设置行合并单元格.registerWriteHandler(new ExcelFillCellMergeStrategyUtils(mergeRowIndex,mergeColumnIndex))//设置行合并单元格.registerWriteHandler(new ExcelFillCelMergeStrategy(cellLineRanges,list.size()-1)).head(CityCapacityPo.class).sheet("sheet1").doWrite(list);} catch (Exception e) {e.printStackTrace();}}

以上就是行和列的合并过程了,主要的内容就是行和列合并的工具类,网上的资料都差不多。其实很多我确实也没参透,只是依样画葫芦,碰巧实现了。

EasyExcel导出合并单元格相关推荐

  1. easyexcel读取合并单元格

    easyexcel读取合并单元格 文章目录 easyexcel读取合并单元格 一.设置读取额外信息 二.重写Listener中的extra()方法,获取合并单元格的信息 三.遍历合并单元格的信息 四. ...

  2. easyexcel处理合并单元格数据

    一.背景 一次工作任务是要解析excel数据,采用阿里的 easyexcel 工具进行解析,由于表格有合并单元格,但是 easyexcel 读取合并单元格只会读取一次,导致下面单元格数据为空,这样会影 ...

  3. easyexcel 动态合并单元格

    easyexcel 动态合并单元格 目前操作excel文档的底层都是用poi来进行的,在早期工作开发过程中,是基于poi,然后对每一个数据单元格进行操作代码编写,后面有一些比较好的开源项目,像easy ...

  4. EasyExcel导入、导出合并单元格excel文件

    原文地址:https://blog.csdn.net/weixin_42195311/article/details/110441885 <!--版本最好大于2.2.6,版本太低会导致没有ext ...

  5. excel格式导出合并单元格

    1.首先看一下,我们导出的模板: 可以看到,导出的模板需要合并单元格,其中在每个项目中工程编号是唯一的,所以需求中有一点,我们必选按照:项目名称+工程编号,作为唯一性来做每个sheet的区分.下面看代 ...

  6. java-easyExcel导出-合并单元格

    实现层: public ResultDto statisticalBudgetDetailExport(HttpServletResponse response, ReimbursementFormD ...

  7. 为什么不居中(CellRangeAddress),关于excel导出合并单元格

    一.最近做一个导出excel需求,按理说很简单,但是发现写公共方法的哥们儿并没有搞合并单元格,而且也不太熟悉他的那种写法,所以简单研究了下,和大家讨论,至少思路千万条,越想越明了. 1.之前的写法简单 ...

  8. easyexcel 列头合并_2020-05-19:EasyExcel自定义合并单元格

    public static void writeExcelWithHeadAndData(OutputStream outputStream, List> head, List> body ...

  9. easyExcel中合并单元格文件读取实现方案

    1.需求场景描述 2.问题分析与实现方案 1.需求场景描述 现在有个业务需要按照指定模板上传选择题,并进行入表处理,使用easyExcel进行文件上传并读取数据,其中涉及合并单元数据读取问题,这里简单 ...

  10. easyExcel自动合并单元格

    来源EasyExcel(根据条件动态合并单元格的重复数据) package com.ustcinfo.fn.comp.complain.util;import com.alibaba.excel.me ...

最新文章

  1. openoffice api java_如何在API / SDK中选择OpenOffice和LibreOffice
  2. android开发4:Android布局管理器1(线性布局,相对布局RelativeLayout-案例)
  3. 51nod 1138 连续整数的和(数学公式)
  4. js date转string_JS之你到底是什么类型?
  5. python之闭包,装饰器
  6. 技术停滞_检测和测试停滞的流– RxJava常见问题解答
  7. javascript-引入-函数的定义与使用-多值传参-ao对象
  8. java 路径通配符_java实现路径通配符*,**,?
  9. PostgreSQL参数学习:random_page_cost
  10. I2C总线协议/地址详解
  11. context deadline exceeded
  12. Kali学习 | 漏洞扫描:3.1 Nessus安装、配置和新建扫描任务
  13. CTF逆向-[GWCTF 2019]babyvm-WP-虚机模拟流程反向编码和z3约束求解器解方程工具的使用
  14. GScoolink GSV2201 TypeC/DP to HDMI2.0
  15. 浙江大学教学实习实践基地落地袋鼠云
  16. 大家能不能在百忙之中 想想鸟姐的话
  17. 2023年最新zabbix监控Linux服务+ensp交换机
  18. 一文了解K8s-概念详解
  19. 对话腾讯马晓轶:游戏投资布局稳健,发起“登月项目”探索未来
  20. python编程超市购物系统_python 自动购物系统 超简单源码(入门级)

热门文章

  1. eclipse快捷键总结
  2. 靶机渗透日记 responder
  3. iOS进阶 - GCD总结
  4. 小包实用工具:国家代码大全
  5. 个人微信支付宝接入GOGO支付免签系统详细教程(图文)
  6. 同时展示多张图片的无缝轮播
  7. 2020年中国报废汽车拆解回收行业市场现状分析,汽车报废率远低于发达国家「图」
  8. 12个“无用”之美,你有没有被惊艳到?
  9. 【智能柜领域】智能快递柜终端系统Axure原型作品(另有智能柜整套作品)
  10. ubuntu 校准时间_ubuntu server自动校正时间 | 学步园