ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

EasyExcel按模板导出(动态合并单元格问题处理)

2021-11-03 18:02:20  阅读:335  来源: 互联网

标签:sheet int EasyExcel 单元格 cell curColIndex curRowIndex 模板


参考网上的链接:

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);
            }
        }
    }

 

 

 

 

 

 

 

标签:sheet,int,EasyExcel,单元格,cell,curColIndex,curRowIndex,模板
来源: https://www.cnblogs.com/gne-hwz/p/15504804.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有