java excel 合并單元格

案例

Excel 導(dǎo)入導(dǎo)出,大部分使用 easy-poi 或者 easy-excel 兩個工具類就可以了,對于簡單的一行一行(像關(guān)系型數(shù)據(jù)庫表記錄)的導(dǎo)出那可真的是啪的一聲,很快啊。

就像下圖這樣:

sheet1

可是要想導(dǎo)出成下圖:

sheet2

這就有點(diǎn)難度了。

工具現(xiàn)成方法

easy-poi

easy-poi注解導(dǎo)出,@Excel 注解有個 needMerge 屬性,屬性描述:是否需要縱向合并單元格(用于含有l(wèi)ist中,單個的單元格,合并list創(chuàng)建的多個row),這個屬性默認(rèn)為false,若為true,則會將當(dāng)前單元格與上一行同列單元格進(jìn)行比較,如果一樣,則會合并單元格,這樣應(yīng)付上圖是可以的,但是要是跨列,好像就不支持了。

easy-excel

easy-excel 注解導(dǎo)出有個 @ContentLoopMerge 注解,表示每隔幾列合并單元格,這樣對于有固定規(guī)律的表格是沒問題的,如果是 23333 這種,應(yīng)該也就不支持了。

利用 poi Api 完成

思路
  1. 首先根據(jù)渲染的數(shù)據(jù),根據(jù)需要合并的屬性,進(jìn)行分組,然后計(jì)算出,合并單元格數(shù)量
  2. 利用easy-poieasy-excel 渲染 Excel ,獲得 Workbook
  3. 再根據(jù)導(dǎo)出sheet名稱,獲取Sheet
  4. 利用Sheet#addMergedRegion方法進(jìn)行合并
  5. done
計(jì)算獲得合并單元格

一般渲染都是list,可以利用 stream 操作進(jìn)行 GroupBy


TreeMap<String, List<E>> treeMap = list.stream()
        .collect(Collectors.groupingBy(key,
        () -> new TreeMap<String, List<E>>(comparator), 
        Collectors.toList()));
        
List<Integer> groups = Lists.newArrayList();
for (Map.Entry<String, List<E>> entry : treeMap.entrySet()) {
    groups.add(entry.getValue().size());
}

這里主要講下,一定要用TreeMap這個結(jié)構(gòu),因?yàn)?code>HashMap這種key是亂序的,一旦亂序,就會與已經(jīng)導(dǎo)出的Excel不一致,一旦不一致,就是亂合并。

所以groupingBy的第二個參數(shù)里面的比較器就尤為重要了,一定要用比較器去控制排序與真實(shí)Excel一致。

分組完畢之后就是將,每個分組size記錄下來,以便進(jìn)行計(jì)算格子。

/**
 * 計(jì)算合并格子
 *
 * @param startRow 表頭最后行
 * @param cols     需要合并的列 數(shù)組
 * @return
 */
public List<CellRangeAddress> computeRange(int startRow, int[] cols) {
    List<CellRangeAddress> mergeCell = Lists.newArrayList();
    for (Integer group : this.groups) {
        int interval = group;
        if (interval == 1) {
            startRow = startRow + 1;
            continue;
        }
        int beginRow = startRow;
        int endRow = beginRow + interval - 1;
        for (int col : cols) {
            CellRangeAddress range = singleRowCellRange(beginRow, endRow, col);
            mergeCell.add(range);
        }
        startRow = endRow + 1;
    }
    return mergeCell;
}

每次只能計(jì)算一個合并列,需要過濾表頭以及知道合并的列,計(jì)算獲得一系列的CellRangeAddress

合并
Sheet sheet = workbook.getSheet(sheetName);
List<CellRangeAddress> addresses = ranges.get(sheetName);
for (CellRangeAddress cellAddresses : addresses) {
    sheet.addMergedRegion(cellAddresses);
}

END

按照這個方法,基本上可以實(shí)現(xiàn)任意合并了,只是稍微有些繁瑣。我自己整理了個工具方法,可以稍微簡化下流程。

SheetMerge<TestEntity> sheetMerge = new SheetMerge(list);
sheetMerge.range("test", TestEntity::getA, (a, b) -> CompareUtil.compare(a, b), new int[]{0}, 1);

ExportParams exportParams = new ExportParams();
exportParams.setSheetName("test");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, TestEntity.class, list);
sheetMerge.merge(workbook);
@Cleanup
BufferedOutputStream outputStream = FileUtil.getOutputStream(file_name);
workbook.write(outputStream);

最后貼下源碼地址:excel-merge

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容