easyexcel导出中自定义合并单元格,通过重写AbstractRowWriteHandler

news2024/9/29 19:16:55

针对 阿里的easyexcel  自定义处理 任意单元格合并

官方给出的合并单元格 只给出固定规律的单元格合并,当然官方也指出可以自定义合并单元格的策略,我们跟进LoopMergeStrategy  这个合并策略的实例类,发现里面继承了AbstractRowWriteHandler,官方示例代码如下

   /**
     * 合并单元格
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link DemoData} {@link DemoMergeData}
     * <p>
     * 2. 创建一个merge策略 并注册
     * <p>
     * 3. 直接写即可
     *
     * @since 2.2.0-beta1
     */
    @Test
    public void mergeWrite() {
        // 方法1 注解
        String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        // 在DemoStyleData里面加上ContentLoopMerge注解
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, DemoMergeData.class).sheet("模板").doWrite(data());

        // 方法2 自定义合并单元格策略
        fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。
        //当然其他合并策略也可以自己写
        LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data());
    }

LoopMergeStrategy 的具体实现

/**
 * The regions of the loop merge
 *
 * @author Jiaju Zhuang
 */
public class LoopMergeStrategy extends AbstractRowWriteHandler {
    /**
     * Each row
     */
    private int eachRow;
    /**
     * Extend column
     */
    private int columnExtend;
    /**
     * The number of the current column
     */
    private int columnIndex;

    public LoopMergeStrategy(int eachRow, int columnIndex) {
        this(eachRow, 1, columnIndex);
    }

    public LoopMergeStrategy(int eachRow, int columnExtend, int columnIndex) {
        if (eachRow < 1) {
            throw new IllegalArgumentException("EachRows must be greater than 1");
        }
        if (columnExtend < 1) {
            throw new IllegalArgumentException("ColumnExtend must be greater than 1");
        }
        if (columnExtend == 1 && eachRow == 1) {
            throw new IllegalArgumentException("ColumnExtend or eachRows must be greater than 1");
        }
        if (columnIndex < 0) {
            throw new IllegalArgumentException("ColumnIndex must be greater than 0");
        }
        this.eachRow = eachRow;
        this.columnExtend = columnExtend;
        this.columnIndex = columnIndex;
    }

    public LoopMergeStrategy(LoopMergeProperty loopMergeProperty, Integer columnIndex) {
        this(loopMergeProperty.getEachRow(), loopMergeProperty.getColumnExtend(), columnIndex);
    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
        Integer relativeRowIndex, Boolean isHead) {
        if (isHead) {
            return;
        }
        if (relativeRowIndex % eachRow == 0) {
            CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum(), row.getRowNum() + eachRow - 1,
                columnIndex, columnIndex + columnExtend - 1);
            writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
        }
    }

}

我们根据官方给出的AbstractRowWriteHandler行处理类 重写:


1.引入jar包

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>easyexcel</artifactId>

<version>2.2.3</version>

</dependency>

2.声明需要合并单元格的定位实例

/**
 * easyExcel 单元格范围设定
 */
@Data
@AllArgsConstructor
public class ExcelCellRange{
    /**
     * 起始行
     */
    private int firstRow;
    /**
     * 终止行
     */
    private int lastRow;
    /**
     * 起始列
     */
    private int firstCol;
    /**
     * 终止列
     */
    private int lastCol;

}

 3.重写自定义合并策略类

/**
 * @Description:EasyExcel自定义合并单元格策略
 * @Date: 2023/4/14 16:11
 */
public class EasyExcelCustomMergeStrategy extends AbstractRowWriteHandler {
    /**
     * 单元格范围
     */
    private List<ExcelCellRange> cellRanges;

    public EasyExcelCustomMergeStrategy(List<ExcelCellRange> cellRanges) {
        this.cellRanges = cellRanges;
    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        if (!isHead) {
            for(ExcelCellRange cellRange :cellRanges)
            {
                if (relativeRowIndex % cellRange.getFirstRow() == 0) {
                    CellRangeAddress cellRangeAddress = new CellRangeAddress(cellRange.getFirstRow(), cellRange.getLastRow(), cellRange.getFirstCol(), cellRange.getLastCol());
                    writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
                }
            }


        }
    }

}

以上封装的实例 ,仅供参考,大家可以自行完善参数校验等逻辑

 4.使用案例

// 定位合并数据
int rowIndex = 1;  // 从第二行开始,因为第一行是表头
//存放合并单元格位置
List<ExcelCellRange> cellRanges = Lists.newArrayListWithCapacity(5);
            cellRanges.add(new ExcelCellRange(0, 1, 0, 0));
            cellRanges.add(new ExcelCellRange(0, 1, 1, 1));
            cellRanges.add(new ExcelCellRange(0, 1, 2, 2));
        
//合并策略
EasyExcelCustomMergeStrategy mergeStrategy = new EasyExcelCustomMergeStrategy(cellRanges);
// 创建工作簿并指定写入的Excel文件
ExcelWriter excelWriter = EasyExcel.write(os)
        .head(TtRoomCheckInStateRes.class)
        .registerWriteHandler(mergeStrategy)
        .build();
// 创建一个只包含一行的Excel表格,用于合并单元格及为表格添加表头
WriteSheet writeSheet = EasyExcel.writerSheet(0, "房间入住情况").build();
//信息写入
excelWriter.write(roomRecordList, writeSheet);
//关闭流
excelWriter.finish();

5.导出效果图

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

揭秘!Chrome 调试的11+隐藏技巧,让你在开发中如虎添翼!

前言 chrome 浏览器作为前端童鞋的老婆&#xff0c;相信你一定不陌生。调页面、写BUG、画样式、看php片少了它整个世界都不香了。 不信&#xff1f;一起来看看我们的老婆有多厉害… 1、一键重新发起请求 在与后端接口联调或排查线上 BUG 时&#xff0c;你是不是也经常听到他…

Python中的主函数

在Python代码中&#xff0c;我们常常看到主函数是以if __name__ __main__开头的&#xff0c;比如 它的原理是什么呢&#xff1f; 首先要知道&#xff0c;__name__是内置变量&#xff0c;用于表示当前模块的名字。在一个模块中运行以下语句&#xff0c;你会发现输出的是__main…

CSS:横向导航栏

横向导航栏&#xff08;盗版导航栏&#xff0c;B站仿写。&#xff09; 原视频链接 <html><head><title>demo</title><style>*{margin: 0;padding: 0;list-style: none;text-decoration: none;}body{display: flex;justify-content: center;a…

模型蒸馏与压缩简单介绍

目录 一、概述 二、DistilBERT模型介绍 2.1 基本结构 2.2 知识蒸馏方法 一、概述 预训练语言模型虽然在众多自然语言任务中取得了很好的效果&#xff0c;但通常这类模型的参数量较大&#xff0c;很难满足实际应用中的时间和空间需求。 下图给出了常见预训练语言模型参数量的…

JDK11 下载与安装、环境配置(全网最详情,值得收藏)

目录 一、下载JDK11 二、安装JDK11 三、配置环境变量 四、验证环境配置是否成功 五、答疑&#xff0c;为什么不配置 CLASSPATH 什么是JDK JDK是 Java 语言的软件开发工具包&#xff0c;主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心&#xff0…

【算法训练(day3)】快速排序模版选择及不同版本快排对比

目录 一.划分区间的选取 二.代码实现lomuto版本快速排序 三.hoare版本快速排序 四.竞赛模板的选取 五.竞赛模板的代码实现 一.划分区间的选取 目前市面上常用的有两种划分区间&#xff0c;一种是hoare划分另一种是Lomuto划分。常见快速排序实现模版比如挖坑法和经典快速排…

第三章(2):深入理解NTLK库基本使用方法

第三章&#xff08;2&#xff09;&#xff1a;深入理解NTLK库基本使用方法 本节主要介绍了NLTK库的基本使用方法&#xff0c;其中对NLTK的安装与配置进行了介绍。随后&#xff0c;对文本处理中常用的分词、句子分割和词性标注这三个任务进行了详细讲解。 如果感觉有用&#xff…

《商用密码应用与安全性评估》第一章密码基础知识1.6密钥交换协议

密码协议是指两个或者两个以上参与者使用密码算法时&#xff0c;为了达到加密保护或安全认证目的而约定的交互规则。 密钥交换协议 公钥密码出现之前&#xff0c;密钥交换很不方便&#xff0c;公钥密码可以在不安全信道上进行交换&#xff0c;交换的密码协议是为了协商会话密钥…

实现开机动画和自定义Toolbar的高级写法

需求是自定义一个Toolbar和全屏展示一个第一次激活App的开机动画 1自定义Toolbar的使用 1仍然是先将工程的theme.xml中设置成NoActionBar <resources xmlns:tools"http://schemas.android.com/tools"><!-- Base application theme. --><style name&…

Oracle11g全新讲解之PLSQL编程

一、PLSQL编程 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言.通过增加变量、控制语句&#xff0c;使我们可以写一些逻辑更加复杂的数据库操作. 语法结构 declare--声明变量 变量名称 v_ 开头&#xff0c;规范 begin--执行具体的语句--异常处理 …

Spring原理学习(五):一篇讲清楚动态代理(jdk和cglib)的使用、原理和源码

目录 一、jdk动态代理的基本使用 二、cglib动态代理的基本使用 2.1 方法一&#xff1a;method.invoke() 方法反射调用 2.2 方法二&#xff08;spring使用的这个方法&#xff09;&#xff1a; methodProxy.invoke() 2.3 方法三&#xff1a;methodProxy.invokeSuper() 三、…

(Linux驱动入门)字符设备

一、设备相关概念 1.1 设备号 内核中通过类型dev_t来描述设备号&#xff0c;其实质是unsigned int 32位整数&#xff0c;其中高12位为主设备号&#xff0c;低20位为次设备号。设备号也是一种资源&#xff0c;当我们需要时可以调用函数去申请。 ​​​​​​​int register_c…

光伏发电数据监控的运维平台

摘要&#xff1a;全球化经济社会的快速发展,加快了传统能源的消耗,导致能源日益短缺,与此同时还带来了严重的环境污染。因此,利用没有环境污染的太阳能进行光伏发电获得了社会的普遍关注。本文根据传统式光伏电站行业的发展背景及其监控系统的技术设备,给出了现代化光伏电站数据…

Vue3通透教程【十二】TS类型声明优势

文章目录 &#x1f31f; 写在前面&#x1f31f; 上篇文章解惑&#x1f31f; JS函数中的隐患&#x1f31f; 函数中的类型&#x1f31f; 写在最后 &#x1f31f; 写在前面 专栏介绍&#xff1a; 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章&#xff0c;应粉丝要求开始更新 V…

计算机视觉 | 八斗人工智能 (中)

目录 卷积&滤波1.一个没有任何效果的卷积核2.平均均值滤波3.图像锐化4.soble边缘检测 卷积的三种填充模式1.padding --> same模式 最常用的模式2.full和valid模式三通道卷积 canny边缘检测算法&#xff08;效果最好&#xff09;Sobel算子、Prewitt算子 相机模型畸变矫正…

新能源汽车和数字化转型

工业时代的代表产品是交通运输设备&#xff0c;核心桂冠是发动机。信息时代的代表产品是智能手机&#xff0c;核心桂冠是芯片。 汽车是个很有代表性产品&#xff0c;因为它既属于复杂高精密金属机械设备&#xff0c;又属于大规模使用的大件消费品。所以这100年来&#xff0c;汽…

代码随想录算法训练营第三十二天|122.买卖股票的最佳时机II 、55. 跳跃游戏 、45.跳跃游戏II

文章目录 122.买卖股票的最佳时机II55. 跳跃游戏45.跳跃游戏II:star: 122.买卖股票的最佳时机II 遇到每天正利润就收集&#xff0c;负利润就不收集 链接:代码随想录 解题思路&#xff1a; ①因为可以多次买卖&#xff0c;所以考虑到最终把最终利润进行分解 如假如第0天买入&am…

垃圾收集算法面试总结

垃圾收集算法 标记 - 清除算法 首先标记出所有需要被回收的对象&#xff0c;标记完后统一回收所有被标记的对象。 后续的收集算法都是基于这种思路并对其不足进行改进而得到的。 这种方法主要有两个缺点&#xff1a; 一个是效率问题&#xff0c;标记和清除两个过程的效率都…

java mysql超市会员积分带抽奖系统

后台相关操作&#xff1a; &#xff08;1&#xff09;系统管理&#xff1a;管理系统的管理员用户。 &#xff08;2&#xff09;会员管理&#xff1a;对会员信息进行增删改功能。 &#xff08;3&#xff09;商品管理&#xff1a;对系统的商品进行增删改查功能等维护。 &#xff…

分治法解二维的最近对问题,算法分析与代码实现,蛮力法与分治法解决二维的最近对问题的区别

&#x1f38a;【数据结构与算法】专题正在持续更新中&#xff0c;各种数据结构的创建原理与运用✨&#xff0c;经典算法的解析✨都在这儿&#xff0c;欢迎大家前往订阅本专题&#xff0c;获取更多详细信息哦&#x1f38f;&#x1f38f;&#x1f38f; &#x1fa94;本系列专栏 -…