EasyExcel-合併單元格

来源:https://www.cnblogs.com/monianxd/archive/2022/06/09/16359369.html
-Advertisement-
Play Games

pom版本 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.7</version> </dependency> 1.自定義合併單元格 在某些業務場景中可能會有合併單 ...


pom版本

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>2.2.7</version>
    </dependency>

1.自定義合併單元格 

在某些業務場景中可能會有合併單元格的需求,下麵具體來說明如何實現

1.1 不合併單元格

先來看下不合併單元格的代碼寫法,簡單複習下 

public static void writeExcel() {
    // 寫excel的路徑,當前項目路徑下
    String fileName = getPath();
    // 構建ExcelWriter
    ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();

    // 構建sheet
    WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class).build();
    // 寫sheet
    excelWriter.write(data1(), writeSheet);
    excelWriter.finish();
  }

  private static String getPath() {
    return System.getProperty("user.dir") + "/" + System.currentTimeMillis() + ".xlsx";
  }

  private static List<DemoData> data1() {
    List<DemoData> list = Lists.newArrayList();
    for (int i = 0; i < 3; i++) {
      DemoData data = new DemoData();
      data.setString("字元串" + 1);
      data.setDate(new Date());
      data.setDoubleData(0.56);
      list.add(data);
    }
    for (int i = 0; i < 3; i++) {
      DemoData data = new DemoData();
      data.setString("字元串" + 2);
      data.setDate(new Date());
      data.setDoubleData(0.56);
      list.add(data);
    }
    for (int i = 0; i < 4; i++) {
      DemoData data = new DemoData();
      data.setString("字元串" + 3);
      data.setDate(new Date());
      data.setDoubleData(0.57);
      list.add(data);
    }
    return list;
  }

  public static void main(String[] args) {
    writeExcel();
  }

打開輸出的excel文件後如下,可以看到單元格沒有合併。現在打算將第一列字元串標題相同的合併

 

1.2 合併單元格

// 自定義合併策略 該類繼承了AbstractMergeStrategy抽象合併策略,需要重寫merge()方法
  public static class CustomMergeStrategy extends AbstractMergeStrategy {

    /**
     * 分組,每幾行合併一次
     */
    private List<Integer> exportFieldGroupCountList;

    /**
     * 目標合併列index
     */
    private Integer targetColumnIndex;

    // 需要開始合併單元格的首行index
    private Integer rowIndex;

    // exportDataList為待合併目標列的值 
    public CustomMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {
      this.exportFieldGroupCountList = getGroupCountList(exportDataList);
      this.targetColumnIndex = targetColumnIndex;
    }


    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {

      if (null == rowIndex) {
        rowIndex = cell.getRowIndex();
      }
      // 僅從首行以及目標列的單元格開始合併,忽略其他
      if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {
        mergeGroupColumn(sheet);
      }
    }

    private void mergeGroupColumn(Sheet sheet) {
      int rowCount = rowIndex;
      for (Integer count : exportFieldGroupCountList) {
        if(count == 1) {
          rowCount += count;
          continue ;
        }
        // 合併單元格
        CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
        sheet.addMergedRegionUnsafe(cellRangeAddress);
        rowCount += count;
      }
    }

    // 該方法將目標列根據值是否相同連續可合併,存儲可合併的行數 
    private List<Integer> getGroupCountList(List<String> exportDataList){
      if (CollectionUtils.isEmpty(exportDataList)) {
        return new ArrayList<>();
      }

      List<Integer> groupCountList = new ArrayList<>();
      int count = 1;

      for (int i = 1; i < exportDataList.size(); i++) {
        if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
          count++;
        } else {
          groupCountList.add(count);
          count = 1;
        }
      }
      // 處理完最後一條後
      groupCountList.add(count);
      return groupCountList;
    }
  }

// 修改WriteSheet的代碼如下 
  public static void writeExcel() {
    String fileName = getPath();
    ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();

    List<DemoData> demoDataList = data1();
    // 寫sheet的時候註冊相應的自定義合併單元格策略
    WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
    .registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
    .build();
    excelWriter.write(demoDataList, writeSheet);
    excelWriter.finish();
  }

打開輸出的excel文件後如下,可以看到第一列有相同值的單元格已經合併了,成功實現 

同理若要合併第三列的數據,則可以在註冊一個sheet寫處理器,代碼如下

  public static void writeExcel() {
    String fileName = getPath();
    ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();

    List<DemoData> demoDataList = data1();
    WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
    .registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
    .registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
    .build();
    excelWriter.write(demoDataList, writeSheet);
    excelWriter.finish();
  }

excel打開如下:

1.3 寫多個sheet

  public static void writeExcel() {
    String fileName = getPath();
    ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();

    List<DemoData> demoDataList = data1();
    WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
    .registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
    .registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
    .build();
    excelWriter.write(demoDataList, writeSheet);

    WriteSheet writeSheet1 = EasyExcel.writerSheet("模板2").head(DemoData.class).build();
    excelWriter.write(data1(), writeSheet1);
    excelWriter.finish();
  }

輸出excel可以看到已經有兩個sheet了

 

1.4 WriteTable

若業務需求要求在同一個sheet中寫多個表,就需要用到WriteTable了。只定義一個WriteSheet,有幾個表就定義幾個WriteTable

  public static void writeExcel01() {
    String fileName = getPath();
    ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
    WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build();

    List<DemoData> demoDataList = data1();
    // 需要表頭設置為true,WriteTable一些屬性會繼承自WriteSheet
    WriteTable writeTable = EasyExcel.writerTable(1).head(DemoData.class).needHead(Boolean.TRUE)
        .registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
        .registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
        .build();
    excelWriter.write(demoDataList, writeSheet, writeTable);

    WriteTable writeTable1 = EasyExcel.writerTable(2).head(DemoData.class).needHead(Boolean.TRUE).build();
    excelWriter.write(data1(), writeSheet, writeTable1);
    excelWriter.finish();
  }

打開excel表格如下 

 

 

結語 

如有錯誤或者優化點歡迎指出,本文參考自EasyExcel文檔


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一個簡單的 vue3 的 websocket hook. 有以下基礎功能: 創建鏈接 失敗重連 發送心跳包 import { ref } from "vue"; export interface WS_CONFIG { url: string; // ws鏈接地址 sendData?: Record ...
  • JavaScript基礎數據類型BigInt實踐,JSON-bigint,bignumber.js,JavaScript精度問題 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 業務背景 近些年來,隨著前端工程架構發展,使得前端項目中也能擁有如後端工程的模塊能力。正所謂 “能力(越)越大(來),責任(越)越大(捲)”,現在的前端工程不僅僅要滿足業務需求,還伴隨更多複雜的環境適配問題,例如: 1.api請求的功能變數名稱會 ...
  • StackOverflow和StackExchange等等都是程式員常用的問題反饋和解決平臺,相當於是專業性更強的知乎。但是很多類似的網站界面打開後總是有一個privacy收集的視窗無法關閉,在很大情況下影響了我們平時的閱讀。因此我們通過前端的屏蔽方法,可以取消privacy位置收集視窗的固定,從而... ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 時間的獲取及時間各格式間的轉換是比較常用的操作,但一是多種語言經常容易弄混,二是同一種語言同一個功能可能有不同的實現函數,導致每次處理時間經常要百度所以來記錄一下。 另外個人真不喜歡同樣功能有多種寫法的形式,從理想角度說多種實現方式讓不同的人都能以其喜歡的方式進行編寫;但實際上當你忘記的時候,你就總 ...
  • 沙包和打傘的故事 美國在1961年到1972年組織實施的一系列載人登月飛行任務。目的是實現載人登月飛行和人對月球的實地考察,為載人行星飛行和探測進行技術準備,它是世界航天史上具有劃時代意義的一項成就。阿波羅計劃始於1961年5月,至1972年12月第6次登月成功結束,歷時約11年,耗資255億美元。 ...
  • 一、分詞 - jieba 優秀的中文分詞庫,依靠中文詞庫,利用詞庫確定漢子之間關聯的概率,形成分詞結果 import jieba word = '偉大的中華人民共和國' jieba.cut(word) jieba.lcut(word) 二、詞雲庫 - wordcloud 對數據中出現頻率較高的 關鍵 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 插件化的需求主要源於對軟體架構靈活性的追求,特別是在開發大型、複雜或需要不斷更新的軟體系統時,插件化可以提高軟體系統的可擴展性、可定製性、隔離性、安全性、可維護性、模塊化、易於升級和更新以及支持第三方開發等方面的能力,從而滿足不斷變化的業務需求和技術挑戰。 一、插件化探索 在WPF中我們想要開 ...
  • 歡迎ReaLTaiizor是一個用戶友好的、以設計為中心的.NET WinForms項目控制項庫,包含廣泛的組件。您可以使用不同的主題選項對項目進行個性化設置,並自定義用戶控制項,以使您的應用程式更加專業。 項目地址:https://github.com/Taiizor/ReaLTaiizor 步驟1: ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...