EasyExcel小試牛刀


原創:轉載需注明原創地址 https://www.cnblogs.com/fanerwei222/p/12029411.html

某種偶然的機會遇到了這個插件, 聽說很牛X, 我之前也不知道, 不過還是耍了一下子, 遂記錄下來.

官方的demo官網都有,傳送門 : https://alibaba-easyexcel.github.io/index.html

當然, 官網的demo只是簡單的演示, 如果你要實現的表格內容比較復雜, 那么需要自己去定義你的數據類, 並且自己去實現, 遂記錄下我實現的一個不簡單也不復雜的表格.

首先看實現的效果圖: 比較粗糙, 不過一般的操作都有

 

 

由於我沒有設置樣式, 所以看起來還是比較丑的, 不過沒關系, 功能實現了, 頁面后面再說嘛.

直接上pom配置:

<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.0.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>

這兩個是必須要的, lombok主要是方便, 我用的EasyExcel版本是2.0.5, 應該可以換成其他的也沒事.

兩個數數據類和一個主類直接貼出來看代碼吧.

package com.domaven.orange.easyExcel;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;

import java.util.Date;
import java.util.List;

/**
 * TODO
 * 示范數據實體
 * {} 括起來的代表着層級標題
 */
@Data
@ContentRowHeight(20)
@HeadRowHeight(20)
@ColumnWidth(25)
public class DemoData {

    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "序號"})
    private String order;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "企業名稱"})
    private String tenantName;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "項目名稱"})
    private String projectName;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "幢號"})
    private Integer houseOrder;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "層數"})
    private Integer flowsNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "規划用途"})
    private String regularUse;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "住宅", "住宅套數"})
    private Integer houseNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "住宅", "住宅面積"})
    private Integer houseArea;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "非住宅", "非住宅套數"})
    private Integer noHouseNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "非住宅", "非住宅面積"})
    private Integer noHouseArea;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "總建築面積"})
    private Integer totalHouseArea;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "許可證號"})
    private Integer admitNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "發證日期"})
    private Date subIdDate;
    /**
     * 小計
     */
    @ExcelIgnore
    private List<TotalData> minTotal;
    /**
     * 總計
     */
    @ExcelIgnore
    private List<TotalData> allTotal;
}
package com.domaven.orange.easyExcel;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
 * TODO
 * 統計數據實體
 */
@Data
public class TotalData {

    @ExcelIgnore
    private String order;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "企業名稱"})
    private String tenantName;

    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "幢號"})
    private Integer houseOrder;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "層數"})
    private Integer flowsNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "規划用途"})
    private String regularUse;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "住宅", "住宅套數"})
    private Integer houseNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "住宅", "住宅面積"})
    private Integer houseArea;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "非住宅", "非住宅套數"})
    private Integer noHouseNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "非住宅", "非住宅面積"})
    private Integer noHouseArea;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "總建築面積"})
    private Integer totalHouseArea;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "許可證號"})
    private Integer admitNums;
    @ExcelProperty({"2019年商品房預售許可證發證統計報表", "發證日期"})
    private Date subIdDate;

    public TotalData setTenantName(String tenantName) {
        this.tenantName = tenantName;
        return this;
    }

    public TotalData setOrder(String order) {
        this.order = order;
        return this;
    }
}
package com.domaven.orange.easyExcel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.merge.LoopMergeStrategy;
import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * TODO
 * 使用EasyExcel按照自己想要的數據格式生成excel
 */
public class MainEasyExcel {

    /**
     * 分批寫入數據
     * @param args
     */
    public static void main(String[] args) {
        /**
         * 文件保存地址
         */
        String fileName = "d://tmp/good.xlsx";

        /**
         * 弄一個寫建造器
         */
        ExcelWriterBuilder builder = EasyExcel.write(fileName, DemoData.class);
        /**
         * 裝點數據
         */
        List<DemoData> list = data();
        /**
         * 將數據按企業名稱進行分組
         */
        Map<String, List<DemoData>> map = list.stream().collect(Collectors.groupingBy(DemoData::getTenantName));

        /**
         * 給除了"小計""總計"等行外的所有有效數據標序號
         */
        final int[] mapOrder = {1};
        map.values().forEach(
                value ->
                    value.forEach(
                            v -> {
                                v.setOrder(String.valueOf(mapOrder[0]));
                                mapOrder[0]++;
                            }
                    )
        );
        List<TotalData> allTotalDataList = new ArrayList<>();
        /**
         * 是否處理總計行標記
         */
        boolean isDepressAllTotal = false;
        /**
         * 從第四行開始合並(下標為3)
         */
        int mergeStartWithRow = 3;
        /**
         * 從第二列開始合並(下標為1)
         */
        int mergeStartWithColumn = 1;
        /**
         * 合並單元格需要用到的參數分別如下
         * firstRowIndex : 起始行索引
         * lastRowIndex : 結束行索引
         * firstColumnIndex : 起始列索引
         * lastColumnIndex : 結束列索引
         */
        int firstRowIndex = 0, lastRowIndex = 0, firstColumnIndex = 0, lastColumnIndex = 0;
        /**
         * 填充數據數量計數器
         */
        int count = 0;
        for (Map.Entry entry : map.entrySet()) {
            /**
             * 設置要合並的單元格的位置
             */
            firstRowIndex = mergeStartWithRow + count;
            lastRowIndex = ((List<DemoData>) entry.getValue()).size() + firstRowIndex - 1;
            firstColumnIndex = mergeStartWithColumn;
            lastColumnIndex = mergeStartWithColumn;
            /**
             * 合並公司名稱行
             */
            builder.registerWriteHandler(getOnceMerge(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex));
            /**
             * 合並小計行
             */
            builder.registerWriteHandler(getOnceMerge(lastRowIndex + 1, lastRowIndex + 1, 0, 1));
            count = count + ((List<DemoData>) entry.getValue()).size() + 1;
        }

        /**
         * 合並總計行
         * 加1是小計那一行
         * 加2是總計那一行
         */
        builder.registerWriteHandler(getOnceMerge(lastRowIndex + 2, lastRowIndex + 2, 0, 1));
        /**
         * 寫器
         */
        ExcelWriter writer = builder.build();
        /**
         * sheet頁
         */
        WriteSheet sheet = EasyExcel.writerSheet("測試").build();
        for (Map.Entry entry : map.entrySet()) {
            /**
             * 分批寫入數據
             */
            writer.write((List<DemoData>) entry.getValue(), sheet);
            /**
             * 寫入小計行數據
             */
            List<TotalData> totalDataList = new ArrayList<>();
            totalDataList.add(((List<DemoData>) (entry.getValue())).get(0).getMinTotal().get(0).setTenantName("小計").setOrder("小計"));
            writer.write(totalDataList, sheet);

            /**
             * 設置總計行數據
             */
            if (!isDepressAllTotal) {
                allTotalDataList.add(((List<DemoData>) (entry.getValue())).get(0).getAllTotal().get(0).setTenantName("總計").setOrder("總計"));
                isDepressAllTotal = true;
            }
        }
        /**
         * 寫入總計行數據
         */
        writer.write(allTotalDataList, sheet);
        writer.finish();

    }

    /**
     * 測試方法, 直接寫入方式
     * @param args
     */
    public static void mainDirect(String[] args) {
        String fileName = "d://tmp/good.xlsx";
        List<DemoData> list = data();
        Map<String, List<DemoData>> map = list.stream().collect(Collectors.groupingBy(DemoData::getTenantName));
        EasyExcel.write(fileName, DemoData.class).sheet("數據模板").doWrite(data());
    }

    /**
     * 按照需要的數據格式構建數據
     * @return
     */
    private static List<DemoData> data() {
        List<DemoData> list = new ArrayList<DemoData>();

        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setOrder(String.valueOf(i));
            if (i % 2 == 0) {
                data.setTenantName("北京科技");
            } else if (i % 3 == 0) {
                data.setTenantName("南京公司");
            } else {
                data.setTenantName("天津包子鋪");
            }
            data.setProjectName("打鐵項目");
            data.setHouseOrder(123);
            data.setFlowsNums(8);
            data.setRegularUse("沒用");
            data.setHouseNums(2);
            data.setHouseArea(120);
            data.setNoHouseNums(4);
            data.setNoHouseArea(400);
            data.setTotalHouseArea(900);
            data.setAdmitNums(8888888);
            data.setAdmitNums(10);
            data.setSubIdDate(new Date());
            /**
             * 特殊的小計和總計數據
             */
            List<TotalData> totalDataList = new ArrayList<>();
            TotalData totalData = new TotalData();
            BeanUtils.copyProperties(data, totalData);
            totalDataList.add(totalData);
            data.setMinTotal(totalDataList);
            data.setAllTotal(totalDataList);
            list.add(data);
        }
        return list;
    }

    /**
     * 獲取樣式策略
     * 阿里官方模板
     * @return
     */
    public static HorizontalCellStyleStrategy getStyle() {
        /**
         * 頭的策略
         */
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        /**
         * 背景設置為紅色
         */
        headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 20);
        headWriteCellStyle.setWriteFont(headWriteFont);
        /**
         * 內容的策略
         */
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        /**
         * 這里需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無法顯示背景顏色.頭默認了 FillPatternType所以可以不指定
         */
        contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        /**
         * 背景綠色
         */
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
        WriteFont contentWriteFont = new WriteFont();
        /**
         * 字體大小
         */
        contentWriteFont.setFontHeightInPoints((short) 20);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        /**
         * 這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現
         */
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        return horizontalCellStyleStrategy;
        /**
         * 這里 需要指定寫用哪個class去寫,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉
         * EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板").doWrite(data());
         */
    }

    /**
     * 獲取合並策略
     * 固定的合並策略,官方模板
     * @return
     */
    public static LoopMergeStrategy getLoopMergeStrategy() {
        /**
         * 每隔2行會合並 把eachColumn 設置成 3 也就是我們數據的長度,所以就第一列會合並。當然其他合並策略也可以自己寫
         */
        LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 1);
        return loopMergeStrategy;
    }

    /**
     * 合並單元格
     * 根據需要指定位置的單元格進行合並
     * @param firstRowIndex 起始行索引
     * @param lastRowIndex 結束行索引
     * @param firstColumnIndex 起始列索引
     * @param lastColumnIndex 結束列索引
     * @return
     */
    public static OnceAbsoluteMergeStrategy getOnceMerge(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) {
        OnceAbsoluteMergeStrategy once = new OnceAbsoluteMergeStrategy(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex);
        return once;
    }

}

代碼注釋也是十分詳盡的, 可以直接看代碼了.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM