首页 > 编程语言 >Java开发笔记之EasyExcel实现自定义合并策略

Java开发笔记之EasyExcel实现自定义合并策略

时间:2022-10-27 22:13:52浏览次数:74  
标签:index sheet 自定义 EasyExcel 合并 fileName new Java DownloadDTO

0x00 概述

本文转载,原文

原本是想学习使用Apache的POI的,但是无意中看到Alibaba的开源工具EastExcel,据说比POI更加快速高效,关键是使用起来也简单。

官网地址为:https://alibaba-easyexcel.github.io/index.html,里面讲解地非常清楚易懂,我这里就不再赘述了,只是记录下写表格时如何通过自定义合并策略来实现动态地合并单元格。

 

0x01 入门例子

如果我们不合并单元格,那么下载的样式将是如下这样的未合并单元格:

那么我们只需要使用如下例子即可:

    @Test
    public void commonWriteTest() {
        String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        EasyExcel.write(fileName, DownloadDTO.class).sheet("sheet名称")
                .doWrite(getFruitData());
    }
    // 模拟从数据库读取需要下载的列表信息
    private List<DownloadDTO> getFruitData() {
        List<DownloadDTO> returnList = new ArrayList<>();
        DownloadDTO d1 = new DownloadDTO();
        d1.setCategory("水果");
        d1.setFruit("苹果");
        d1.setColor("红色");
        d1.setProduceDate(new Date());

        DownloadDTO d2 = new DownloadDTO();
        BeanUtils.copyProperties(d1, d2);
        d2.setColor("绿色");

        DownloadDTO d3 = new DownloadDTO();
        BeanUtils.copyProperties(d1, d3);
        d2.setColor("白色");

        DownloadDTO t1 = new DownloadDTO();
        t1.setCategory("水果");
        t1.setFruit("香蕉");
        t1.setColor("黄色");
        t1.setProduceDate(new Date());

        DownloadDTO t2 = new DownloadDTO();
        BeanUtils.copyProperties(t1, t2);
        t2.setColor("青色");

        returnList.add(d1);
        returnList.add(d2);
        returnList.add(d3);
        returnList.add(t1);
        returnList.add(t2);
        return returnList;
    }
@Data
public class DownloadDTO {
    @ExcelProperty(value = "物品种类", index = 0)
    private String category;
    @ExcelProperty(value = "水果名称", index = 1)
    private String fruit;
    @ExcelProperty(value = "水果颜色", index = 2)
    private String color;
    @ExcelProperty(value = "水果产期", index = 3)
    private Date produceDate;
}

其中,方法getFruitDataDownloadDTO在后面的例子中还会用到,就不再写出。

如果我们想要合并单元格,那么官方文档上的例子是这样的loopMerge:

 

与之对应的代码如下:

    @Test
    public void loopMergeStrategyTest() {
        String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        // 将第一列的数据每隔两行进行合并
        LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
        EasyExcel.write(fileName, DownloadDTO.class).registerWriteHandler(loopMergeStrategy)
                .sheet("sheet名称").doWrite(getFruitData());
    }

其中LoopMergeStrategy的源码其实也很简单,底层还是用到了apache poi的API:

    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        if (relativeRowIndex != null) {
            Integer currentColumnIndex;
            if (head != null) {
                currentColumnIndex = head.getColumnIndex();
            } else {
                currentColumnIndex = cell.getColumnIndex();
            }

            // 将入参中指定的列this.columnIndex按照每this.eachRow行进行合并,this.eachRow也是入参
            if (currentColumnIndex == this.columnIndex && relativeRowIndex % this.eachRow == 0) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex() + this.eachRow - 1, cell.getColumnIndex(), cell.getColumnIndex() + this.columnCount - 1);
                sheet.addMergedRegionUnsafe(cellRangeAddress);
            }

        }
    }

然后,在github的issue中,有这样一个使用OnceAbsoluteMergeStrategy的例子onceAbsoluteMerge:

在这个例子中,我们可以指定坐标范围,对固定区间进行合并,其对应的代码如下:

    @Test
    public void onceMergeStrategyTest() {
        String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(1, 3, 1, 1);
        EasyExcel.write(fileName, DownloadDTO.class).registerWriteHandler(onceAbsoluteMergeStrategy)
                .sheet("sheet名称").doWrite(getFruitData());
    }

当然了,我们可以一次使用多个合并策略,比如我们想实现这样的效果onceAbsoluteMerge2:

OnceAbsoluteMergeStrategy可以这么做:

    @Test
    public void onceMergeStrategyTest() {
        String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(1, 3, 1, 1);
        OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy2 = new OnceAbsoluteMergeStrategy(4, 5, 1, 1);
        EasyExcel.write(fileName, DownloadDTO.class)
                .registerWriteHandler(onceAbsoluteMergeStrategy)
                .registerWriteHandler(onceAbsoluteMergeStrategy2)
                .sheet("sheet名称").doWrite(getFruitData());
    }

 

0x02 自定义实现合并策略

当我们需要在写Excel的时候实现更加复杂乃至动态地合并单元格时,就需要自己实现一个合并策略。

比如当我们想实现这样的效果时myMerge:

在这个例子中,对于第1、4列,我们需要根据记录总数,都合并成一个单元格;

对于第2列,我们需要根据每组的记录个数,分别进行单元格的合并;而对于第3列,则不要使用合并策略。

与之对应的代码是:

    @Test
    public void myMergeStrategyTest() {
        String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        MyMergeStrategy myMergeStrategy = new MyMergeStrategy(getFruitData(), getGroupData());
        EasyExcel.write(fileName, DownloadDTO.class).registerWriteHandler(myMergeStrategy)
                .sheet("sheet名称").doWrite(getFruitData());
    }
public class MyMergeStrategy extends AbstractMergeStrategy {

    private List<DownloadDTO> fruitList;
    private List<Integer> fruitGroupCount;
    private Sheet sheet;

    public MyMergeStrategy(List<DownloadDTO> fruitList, List<Integer> fruitGroupCount) {
        this.fruitList = fruitList;
        this.fruitGroupCount = fruitGroupCount;
    }

    // 将该列全部合并成一个单元格
    private void mergeCommonColumn(Integer index) {
        CellRangeAddress cellRangeAddress = new CellRangeAddress(1, fruitList.size(), index, index);
        sheet.addMergedRegionUnsafe(cellRangeAddress);
    }

    // 按照分组将各种类别分别合并成一个单元格
    private void mergeGroupColumn(Integer index) {
        Integer rowCnt = 1;
        for (Integer count : fruitGroupCount) {
            CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCnt, rowCnt + count - 1, index, index);
            sheet.addMergedRegionUnsafe(cellRangeAddress);
            rowCnt += count;
        }
    }

    @Override
    protected void merge(org.apache.poi.ss.usermodel.Sheet sheet, Cell cell, Head head, Integer integer) {
        this.sheet = sheet;
        if (cell.getRowIndex() == 1) {
            switch (cell.getColumnIndex()) {
                case 0:
                    this.mergeCommonColumn(0);
                    break;
                case 1:
                    this.mergeGroupColumn(1);
                    break;
                case 2:
                    break;
                case 3:
                    this.mergeCommonColumn(3);
                    break;
                default:
                    break;
            }
        }
    }
}

为什么不使用多个OnceAbsouluteMergeStrategy?

因为我们在写代码的时候并不知道每个分组的数量究竟有多少个,所以只能自己写合适的合并策略了。

 

标签:index,sheet,自定义,EasyExcel,合并,fileName,new,Java,DownloadDTO
From: https://www.cnblogs.com/JetpropelledSnake/p/16834172.html

相关文章

  • java - ServletContext
    ServletContext:web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用;作用:共享数据---->我们在这个servlet保存的数据可以在......
  • Java反射
    Java反射作用原理:反射机制在运行时,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意个对象,都能够调用它的任意一个方法,在Java中,只要给定类的名字,就可以通过反射......
  • 学习java第一天
    关键字public权限修饰符表示公共的,任何地方都可以用class类的修饰符。static表示静态的void表示没有返回结果main主方法的名字,main方法是程序的入......
  • javaSE基础-比较器
    Java比较器1、java对象正常情况下只能进行==或!=,不能进行比较大小。若需要比较对象的大小,需要实现两个接口中的任何一个:Comparable或Comparator2、Comparable接口......
  • JavaScript数组相关操作方法以及数组扩展与修复
    JavaScript一些常用的操作方法join()将数组中所有元素转化为字符串并连接一起,返回最后生成的字符串。可以指定分隔符;vararr=[23,56,78,0,98,190];consol......
  • JavaScript设计模式-行为设计模式
    行为设计模式用于不同对象之间职责划分、算法抽象,包含:模板方法模式、观察者模式、状态模式、策略模式、职责链模式、命令模式、访问者模式、中介模式、备忘录模式、迭代器模......
  • JavaScript设计模式-结构型设计模式
    结构型设计模式关注如何把类或者对象组合成为更大、更复杂的结构,简化设计。包含:外观模式、适配器模式、代理模式、装饰者模式、桥接模式、组合模式、享元模式外观模式(套餐服......
  • JavaScript中的
    "=="和"==="运算符使用于比较两个值是否相等。都允许任意类型的操作数,若操作数相等则返回true,否则返回false。"===":严格相等运算符(恒等运算符),用来检测两个操作数是......
  • JavaScript中易忘的运算符
    eval()JavaScript通过全局函数eval()可以解释运行由JavaScript源码组成的字符串并且产生一个值。eval("25*4");//==100eval()是一个原本是一个函数,但是已经被当成运算符来......
  • JavaScript函数进阶
    JavaScript中函数是第一类对象。函数与对象共存,函数也可以被视为其他人一类型的JavaScript对象。函数能被变量引用、能以字面量形式声名,甚至可以作为函数参数进行传递。Java......