EasyExcel實現(xiàn)自定義合并策略

前言

原本是想學(xué)習(xí)使用Apache的POI的,但是無意中看到Alibaba的開源工具EastExcel,據(jù)說比POI更加快速高效,關(guān)鍵是使用起來也簡單。

官網(wǎng)地址為:https://alibaba-easyexcel.github.io/index.html,里面講解地非常清楚易懂,我這里就不再贅述了,只是記錄下寫表格時如何通過自定義合并策略來實現(xiàn)動態(tài)地合并單元格。

入門例子

如果我們不合并單元格,那么下載的樣式將是如下這樣的:


未合并單元格

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

    @Test
    public void commonWriteTest() {
        String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        EasyExcel.write(fileName, DownloadDTO.class).sheet("sheet名稱")
                .doWrite(getFruitData());
    }
    // 模擬從數(shù)據(jù)庫讀取需要下載的列表信息
    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 = "水果產(chǎn)期", index = 3)
    private Date produceDate;
}

其中,方法getFruitDataDownloadDTO在后面的例子中還會用到,就不再寫出。

如果我們想要合并單元格,那么官方文檔上的例子是這樣的:


loopMerge

與之對應(yīng)的代碼如下:

    @Test
    public void loopMergeStrategyTest() {
        String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        // 將第一列的數(shù)據(jù)每隔兩行進(jìn)行合并
        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();
            }

            // 將入?yún)⒅兄付ǖ牧衪his.columnIndex按照每this.eachRow行進(jìn)行合并,this.eachRow也是入?yún)?            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

在這個例子中,我們可以指定坐標(biāo)范圍,對固定區(qū)間進(jìn)行合并,其對應(yīng)的代碼如下:

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

當(dāng)然了,我們可以一次使用多個合并策略,比如我們想實現(xiàn)這樣的效果:


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

自定義實現(xiàn)合并策略

當(dāng)我們需要在寫Excel的時候?qū)崿F(xiàn)更加復(fù)雜乃至動態(tài)地合并單元格時,就需要自己實現(xiàn)一個合并策略。

比如當(dāng)我們想實現(xiàn)這樣的效果時:


myMerge

在這個例子中,對于第1、4列,我們需要根據(jù)記錄總數(shù),都合并成一個單元格;對于第2列,我們需要根據(jù)每組的記錄個數(shù),分別進(jìn)行單元格的合并;而對于第3列,則不要使用合并策略。

與之對應(yīng)的代碼是:

    @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?

因為我們在寫代碼的時候并不知道每個分組的數(shù)量究竟有多少個,所以只能自己寫合適的合并策略了。

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

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

  • 轉(zhuǎn)自鏈接 目錄 1.認(rèn)識NPOI 2.使用NPOI生成xls文件 2.1創(chuàng)建基本內(nèi)容 2.1.1創(chuàng)建Workboo...
    腿毛褲閱讀 11,165評論 1 3
  • 翻譯自“Collection View Programming Guide for iOS” 0 關(guān)于iOS集合視...
    lakerszhy閱讀 4,083評論 1 22
  • 使用首先需要了解他的工作原理 1.POI結(jié)構(gòu)與常用類 (1)創(chuàng)建Workbook和Sheet (2)創(chuàng)建單元格 (...
    長城ol閱讀 8,755評論 2 25
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,689評論 1 32
  • 同樣是餐飲行業(yè),為什么“飛鴿小?!毕啾绕饋?,特色更加的鮮明,更能讓人一眼就記住呢?其實是因為“飛鴿小棧”本身具備優(yōu)...
    飛鴿小棧閱讀 379評論 0 0

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