zoukankan      html  css  js  c++  java
  • EasyExcel按模板导出(动态合并单元格问题处理)

    参考网上的链接:

    EasyExcel按模板导出与下载(自定义合并单元格)
    https://blog.csdn.net/weixin_44511845/article/details/120290264
    EasyExcel(根据条件动态合并单元格的重复数据))
    https://blog.csdn.net/Violet_201903027/article/details/105724907

    编写模板导出时,某一列单元格合并功能

    上面的资料使用的EasyExcel版本是:2.1.7

    我使用的版本是:2.2.0-beta2

    使用资料代码进行模板导出同时,动态单元格合并

    github官方提供了 LoopMergeStrategy 合并策略 在模板导出不生效。因为LoopMergeStrategy extends AbstractRowWriteHandler ,使用 afterRowDispose() 行操作完成后执行合并操作。

    但是在模板导出过程中afterRowDispose() 方法没有被触发。

    合并策略类:ExcelFillCellMergeStrategy 

     1 public class ExcelFillCellMergeStrategy implements CellWriteHandler {
     2 
     3     /** 需要进行单元格合并的列数组 **/
     4     private int[] mergeColumnIndex;
     5     /** 单元格合并从第几行开始 **/
     6     private int mergeRowIndex;
     7 
     8     public ExcelFillCellMergeStrategy() {}
     9 
    10     public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
    11         this.mergeRowIndex = mergeRowIndex;
    12         this.mergeColumnIndex = mergeColumnIndex;
    13     }
    14  。。。
    15  。。。
    16 
    17     @Override
    18     public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
    19         List<CellData> list, Cell cell, Head head, Integer integer, Boolean isHead) {
    20         int curRowIndex = cell.getRowIndex();
    21         int curColIndex = cell.getColumnIndex();
    22         if (curRowIndex > mergeRowIndex) {
    23             for (int i = 0; i < mergeColumnIndex.length; i++) {
    24                 if (curColIndex == mergeColumnIndex[i]) {
    25                     mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
    26                     break;
    27                 }
    28             }
    29         }
    30     }
    31 
    32     /**
    33      * 当前单元格向上合并
    34      *
    35      * @param writeSheetHolder
    36      * @param cell
    37      *            当前单元格
    38      * @param curRowIndex
    39      *            当前行
    40      * @param curColIndex
    41      *            当前列
    42      */
    43     private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
    44         Object curData =
    45             cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
    46         Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
    47         Object preData =
    48             preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
    49         // 将当前单元格数据与上一个单元格数据比较
    50         Boolean dataBool = preData.equals(curData);
    51         if (dataBool) {
    52             Sheet sheet = writeSheetHolder.getSheet();
    53             List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
    54             boolean isMerged = false;
    55             for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
    56                 CellRangeAddress cellRangeAddr = mergeRegions.get(i);
    57                 // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
    58                 if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
    59                     sheet.removeMergedRegion(i);
    60                     cellRangeAddr.setLastRow(curRowIndex);
    61                     sheet.addMergedRegion(cellRangeAddr);
    62                     isMerged = true;
    63                 }
    64             }
    65             // 若上一个单元格未被合并,则新增合并单元
    66             if (!isMerged) {
    67                 CellRangeAddress cellRangeAddress =
    68                     new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
    69                 sheet.addMergedRegion(cellRangeAddress);
    70             }
    71         }
    72     }
    73 }

    测试代码

        @Test
        public void fillTest1() throws IOException {
            // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"{","}"代替
            // 填充list 的时候还要注意 模板中{.} 多了个点 表示list
            String templatePath = EasyexcelAnnotationFillTest.class.getResource("/").getPath();
            templatePath = templatePath + "fillTemplate.xlsx";
            OutputStream outputStream = new FileOutputStream("E:/测试填充数据.xlsx");
    
            // 填充列表数据
            List<FillWithAnnotationData> listData = getFillListData();
            // 第一列进行单元格合并
            int[] mergeColumeIndex = {0};
            // 从第4行开始合并
            int mergeRowIndex = 3;
    
            ExcelWriter excelWriter = EasyExcelFactory.write(outputStream)
                    .withTemplate(templatePath)
                    //设置合并单元格策略
                    .registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex, mergeColumeIndex))
                    .build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            excelWriter.fill(listData, writeSheet);
            excelWriter.finish();
            outputStream.close();
        }

    public List<FillWithAnnotationData> getFillListData() {
    List<FillWithAnnotationData> listData = new ArrayList<>();
    for (int i=0; i < 10; i++) {
    FillWithAnnotationData data = new FillWithAnnotationData();
    data.setName("名称");
    data.setMoney(new BigDecimal(1002.35+i).toPlainString());
    data.setNumber(1002.35+i);
    listData.add(data);
    }
    return listData;
    }
    
    
    public class FillWithAnnotationData {

    private String name;
    @NumberFormat(",##0.00")
    @ExcelFillProperty(converter = StringNumberConverter.class)
    private String money;
    @NumberFormat(",##0.00")
    @ExcelFillProperty(converter = DoubleStringConverter.class)
    private Double number;
    }
     

    测试模板如下图

    报错位置:ExcelFillCellMergeStrategy合并策略类的 mergeWithPrevRow()方法中

    第46行位置

    Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);

    这一行代码会报空指针异常 java.lang.NullPointerException

    原因:

    debug发现,cell.getSheet() 行的下标第0到3的数据行,获取的是同一个 sheet 实例

    当下标为4时,执行cell.getSheet()获取到的 sheet 实例不一样,而且里面的sheet存在的row数据,只有下标为4以后的

     而下标0到3的行数据被存储到 存储sheet中。

    writeSheetHolder.getCachedSheet()

    所以改进合并策略类的合并方法:

    当获取不到前一行数据时,查找缓存sheet中的行数据

    /**
         * 当前单元格向上合并
         *
         * @param writeSheetHolder
         * @param cell
         *            当前单元格
         * @param curRowIndex
         *            当前行
         * @param curColIndex
         *            当前列
         */
        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();
            // 将当前单元格数据与上一个单元格数据比较
            Boolean dataBool = preData.equals(curData);
            if (dataBool) {
                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);
                }
            }
        }

    作者:海绵般汲取
    出处:https://www.cnblogs.com/gne-hwz/
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
  • 相关阅读:
    第四阶段学习总结
    第三阶段学习总结
    第二阶段学习总结
    第一阶段内容的学习总结
    第四单元及OO课程总结
    关于工具的碎碎念
    第三单元博客总结
    第二单元博客总结
    第一单元作业总结
    实验五 单元测试
  • 原文地址:https://www.cnblogs.com/gne-hwz/p/15504804.html
Copyright © 2011-2022 走看看