JAVA連接Excel最好用的開源項目EasyExcel,官方使用文檔及.jar包下載

EasyExcel是一個基於Java的簡單、省內存的讀寫Excel的開源項目。在儘可能節約內存的情況下支持讀寫百M的Excel。
github地址:https://github.com/alibaba/easyexcel
開源項目不容易,如果覺得本項目對您的工作還是有幫助的話,請在幫忙在github star點個★Star。

我使用後,覺得阿里確實很用心,使用簡單,速度還快,這個⭐可以給。
如果以下內容還是看不懂,給他們點個小星星,然後我教你,嘻嘻。

jar下載地址:https://share.weiyun.com/5ADw1oz

讀excel的DEMO文檔

package com.alibaba.easyexcel.test.demo.read;

import java.io.File;
import java.util.List;
import java.util.Map;

import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;

/**
 * 讀的常見寫法
 *
 * @author Jiaju Zhuang
 */
@Ignore
public class ReadTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(ReadTest.class);

    /**
     * 最簡單的讀
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoDataListener}
     * <p>
     * 3. 直接讀即可
     */
    @Test
    public void simpleRead() {
        // 有個很重要的點 DemoDataListener 不能被spring管理,要每次讀取excel都要new,然後裏面用到spring可以構造方法傳進去
        // 寫法1:
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet 文件流會自動關閉
        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();

        // 寫法2:
        fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
        ReadSheet readSheet = EasyExcel.readSheet(0).build();
        excelReader.read(readSheet);
        // 這裏千萬別忘記關閉,讀的時候會創建臨時文件,到時磁盤會崩的
        excelReader.finish();
    }

    /**
     * 指定列的下標或者列名
     *
     * <p>
     * 1. 創建excel對應的實體對象,並使用{@link ExcelProperty}註解. 參照{@link IndexOrNameData}
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link IndexOrNameDataListener}
     * <p>
     * 3. 直接讀即可
     */
    @Test
    public void indexOrNameRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏默認讀取第一個sheet
        EasyExcel.read(fileName, IndexOrNameData.class, new IndexOrNameDataListener()).sheet().doRead();
    }

    /**
     * 讀多個或者全部sheet,這裏注意一個sheet不能讀取多次,多次讀取需要重新讀取文件
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoDataListener}
     * <p>
     * 3. 直接讀即可
     */
    @Test
    public void repeatedRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 讀取全部sheet
        // 這裏需要注意 DemoDataListener的doAfterAllAnalysed 會在每個sheet讀取完畢後調用一次。然後所有sheet都會往同一個DemoDataListener裏面寫
        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();

        // 讀取部分sheet
        fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        ExcelReader excelReader = EasyExcel.read(fileName).build();
        // 這裏爲了簡單 所以註冊了 同樣的head 和Listener 自己使用功能必須不同的Listener
        ReadSheet readSheet1 =
            EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
        ReadSheet readSheet2 =
            EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
        // 這裏注意 一定要把sheet1 sheet2 一起傳進去,不然有個問題就是03版的excel 會讀取多次,浪費性能
        excelReader.read(readSheet1, readSheet2);
        // 這裏千萬別忘記關閉,讀的時候會創建臨時文件,到時磁盤會崩的
        excelReader.finish();
    }

    /**
     * 日期、數字或者自定義格式轉換
     * <p>
     * 默認讀的轉換器{@link DefaultConverterLoader#loadDefaultReadConverter()}
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link ConverterData}.裏面可以使用註解{@link DateTimeFormat}、{@link NumberFormat}或者自定義註解
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link ConverterDataListener}
     * <p>
     * 3. 直接讀即可
     */
    @Test
    public void converterRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet
        EasyExcel.read(fileName, ConverterData.class, new ConverterDataListener())
            // 這裏注意 我們也可以registerConverter來指定自定義轉換器, 但是這個轉換變成全局了, 所有java爲string,excel爲string的都會用這個轉換器。
            // 如果就想單個字段使用請使用@ExcelProperty 指定converter
            // .registerConverter(new CustomStringStringConverter())
            // 讀取sheet
            .sheet().doRead();
    }

    /**
     * 多行頭
     *
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoDataListener}
     * <p>
     * 3. 設置headRowNumber參數,然後讀。 這裏要注意headRowNumber如果不指定, 會根據你傳入的class的{@link ExcelProperty#value()}裏面的表頭的數量來決定行數,
     * 如果不傳入class則默認爲1.當然你指定了headRowNumber不管是否傳入class都是以你傳入的爲準。
     */
    @Test
    public void complexHeaderRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet
        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet()
            // 這裏可以設置1,因爲頭就是一行。如果多行頭,可以設置其他值。不傳入也可以,因爲默認會根據DemoData 來解析,他沒有指定頭,也就是默認1行
            .headRowNumber(1).doRead();
    }

    /**
     * 讀取表頭數據
     *
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoHeadDataListener}
     * <p>
     * 3. 直接讀即可
     */
    @Test
    public void headerRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet
        EasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead();
    }

    /**
     * 額外信息(批註、超鏈接、合併單元格信息讀取)
     * <p>
     * 由於是流式讀取,沒法在讀取到單元格數據的時候直接讀取到額外信息,所以只能最後通知哪些單元格有哪些額外信息
     *
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoExtraData}
     * <p>
     * 2. 由於默認異步讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoExtraListener}
     * <p>
     * 3. 直接讀即可
     *
     * @since 2.2.0-beat1
     */
    @Test
    public void extraRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "extra.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet
        EasyExcel.read(fileName, DemoExtraData.class, new DemoExtraListener())
            // 需要讀取批註 默認不讀取
            .extraRead(CellExtraTypeEnum.COMMENT)
            // 需要讀取超鏈接 默認不讀取
            .extraRead(CellExtraTypeEnum.HYPERLINK)
            // 需要讀取合併單元格信息 默認不讀取
            .extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
    }

    /**
     * 讀取公式和單元格類型
     *
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link CellDataReadDemoData}
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoHeadDataListener}
     * <p>
     * 3. 直接讀即可
     *
     * @since 2.2.0-beat1
     */
    @Test
    public void cellDataRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "cellDataDemo.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet
        EasyExcel.read(fileName, CellDataReadDemoData.class, new CellDataDemoHeadDataListener()).sheet().doRead();
    }

    /**
     * 數據轉換等異常處理
     *
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link ExceptionDemoData}
     * <p>
     * 2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoExceptionListener}
     * <p>
     * 3. 直接讀即可
     */
    @Test
    public void exceptionRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet
        EasyExcel.read(fileName, ExceptionDemoData.class, new DemoExceptionListener()).sheet().doRead();
    }

    /**
     * 同步的返回,不推薦使用,如果數據量大會把數據放到內存裏面
     */
    @Test
    public void synchronousRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet 同步讀取會自動finish
        List<DemoData> list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync();
        for (DemoData data : list) {
            LOGGER.info("讀取到數據:{}", JSON.toJSONString(data));
        }

        // 這裏 也可以不指定class,返回一個list,然後讀取第一個sheet 同步讀取會自動finish
        List<Map<Integer, String>> listMap = EasyExcel.read(fileName).sheet().doReadSync();
        for (Map<Integer, String> data : listMap) {
            // 返回每條數據的鍵值對 表示所在的列 和所在列的值
            LOGGER.info("讀取到數據:{}", JSON.toJSONString(data));
        }
    }

    /**
     * 不創建對象的讀
     */
    @Test
    public void noModelRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 這裏 只要,然後讀取第一個sheet 同步讀取會自動finish
        EasyExcel.read(fileName, new NoModelDataListener()).sheet().doRead();
    }
}

寫excel的DEMO文檔

package com.alibaba.easyexcel.test.demo.write;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.junit.Ignore;
import org.junit.Test;

import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
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 com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.write.merge.LoopMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;

/**
 * 寫的常見寫法
 *
 * @author Jiaju Zhuang
 */
@Ignore
public class WriteTest {
    /**
     * 最簡單的寫
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 直接寫即可
     */
    @Test
    public void simpleWrite() {
        // 寫法1
        String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        // 如果這裏想使用03 則 傳入excelType參數即可
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

        // 寫法2
        fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫
        ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
        WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
        excelWriter.write(data(), writeSheet);
        /// 千萬別忘記finish 會幫忙關閉流
        excelWriter.finish();
    }

    /**
     * 根據參數只導出指定列
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 根據自己或者排除自己需要的列
     * <p>
     * 3. 直接寫即可
     *
     * @since 2.1.1
     */
    @Test
    public void excludeOrIncludeWrite() {
        String fileName = TestFileUtil.getPath() + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";

        // 根據用戶傳入字段 假設我們要忽略 date
        Set<String> excludeColumnFiledNames = new HashSet<String>();
        excludeColumnFiledNames.add("date");
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板")
            .doWrite(data());

        fileName = TestFileUtil.getPath() + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
        // 根據用戶傳入字段 假設我們只要導出 date
        Set<String> includeColumnFiledNames = new HashSet<String>();
        includeColumnFiledNames.add("date");
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("模板")
            .doWrite(data());
    }

    /**
     * 指定寫入的列
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link IndexData}
     * <p>
     * 2. 使用{@link ExcelProperty}註解指定寫入的列
     * <p>
     * 3. 直接寫即可
     */
    @Test
    public void indexWrite() {
        String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data());
    }

    /**
     * 複雜頭寫入
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link ComplexHeadData}
     * <p>
     * 2. 使用{@link ExcelProperty}註解指定複雜的頭
     * <p>
     * 3. 直接寫即可
     */
    @Test
    public void complexHeadWrite() {
        String fileName = TestFileUtil.getPath() + "complexHeadWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data());
    }

    /**
     * 重複多次寫入
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link ComplexHeadData}
     * <p>
     * 2. 使用{@link ExcelProperty}註解指定複雜的頭
     * <p>
     * 3. 直接調用二次寫入即可
     */
    @Test
    public void repeatedWrite() {
        // 方法1 如果寫到同一個sheet
        String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫
        ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
        // 這裏注意 如果同一個sheet只要創建一次
        WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
        // 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來
        for (int i = 0; i < 5; i++) {
            // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
            List<DemoData> data = data();
            excelWriter.write(data, writeSheet);
        }
        /// 千萬別忘記finish 會幫忙關閉流
        excelWriter.finish();

        // 方法2 如果寫到不同的sheet 同一個對象
        fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 指定文件
        excelWriter = EasyExcel.write(fileName, DemoData.class).build();
        // 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來。這裏最終會寫到5個sheet裏面
        for (int i = 0; i < 5; i++) {
            // 每次都要創建writeSheet 這裏注意必須指定sheetNo 而且sheetName必須不一樣
            writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
            // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
            List<DemoData> data = data();
            excelWriter.write(data, writeSheet);
        }
        /// 千萬別忘記finish 會幫忙關閉流
        excelWriter.finish();

        // 方法3 如果寫到不同的sheet 不同的對象
        fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 指定文件
        excelWriter = EasyExcel.write(fileName).build();
        // 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來。這裏最終會寫到5個sheet裏面
        for (int i = 0; i < 5; i++) {
            // 每次都要創建writeSheet 這裏注意必須指定sheetNo 而且sheetName必須不一樣。這裏注意DemoData.class 可以每次都變,我這裏爲了方便 所以用的同一個class 實際上可以一直變
            writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build();
            // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
            List<DemoData> data = data();
            excelWriter.write(data, writeSheet);
        }
        /// 千萬別忘記finish 會幫忙關閉流
        excelWriter.finish();
    }

    /**
     * 日期、數字或者自定義格式轉換
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link ConverterData}
     * <p>
     * 2. 使用{@link ExcelProperty}配合使用註解{@link DateTimeFormat}、{@link NumberFormat}或者自定義註解
     * <p>
     * 3. 直接寫即可
     */
    @Test
    public void converterWrite() {
        String fileName = TestFileUtil.getPath() + "converterWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, ConverterData.class).sheet("模板").doWrite(data());
    }

    /**
     * 圖片導出
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link ImageData}
     * <p>
     * 2. 直接寫即可
     */
    @Test
    public void imageWrite() throws Exception {
        String fileName = TestFileUtil.getPath() + "imageWrite" + System.currentTimeMillis() + ".xlsx";
        // 如果使用流 記得關閉
        InputStream inputStream = null;
        try {
            List<ImageData> list = new ArrayList<ImageData>();
            ImageData imageData = new ImageData();
            list.add(imageData);
            String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg";
            // 放入五種類型的圖片 實際使用只要選一種即可
            imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
            imageData.setFile(new File(imagePath));
            imageData.setString(imagePath);
            inputStream = FileUtils.openInputStream(new File(imagePath));
            imageData.setInputStream(inputStream);
            imageData.setUrl(new URL(
                "https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg"));
            EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    /**
     * 根據模板寫入
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link IndexData}
     * <p>
     * 2. 使用{@link ExcelProperty}註解指定寫入的列
     * <p>
     * 3. 使用withTemplate 寫取模板
     * <p>
     * 4. 直接寫即可
     */
    @Test
    public void templateWrite() {
        String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        String fileName = TestFileUtil.getPath() + "templateWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, DemoData.class).withTemplate(templateFileName).sheet().doWrite(data());
    }

    /**
     * 列寬、行高
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link WidthAndHeightData}
     * <p>
     * 2. 使用註解{@link ColumnWidth}、{@link HeadRowHeight}、{@link ContentRowHeight}指定寬度或高度
     * <p>
     * 3. 直接寫即可
     */
    @Test
    public void widthAndHeightWrite() {
        String fileName = TestFileUtil.getPath() + "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, WidthAndHeightData.class).sheet("模板").doWrite(data());
    }

    /**
     * 註解形式自定義樣式
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoStyleData}
     * <p>
     * 3. 直接寫即可
     *
     * @since 2.2.0-beta1
     */
    @Test
    public void annotationStyleWrite() {
        String fileName = TestFileUtil.getPath() + "annotationStyleWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, DemoStyleData.class).sheet("模板").doWrite(data());
    }

    /**
     * 攔截器形式自定義樣式
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 創建一個style策略 並註冊
     * <p>
     * 3. 直接寫即可
     */
    @Test
    public void handlerStyleWrite() {
        String fileName = TestFileUtil.getPath() + "handlerStyleWrite" + System.currentTimeMillis() + ".xlsx";
        // 頭的策略
        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);

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

    /**
     * 合併單元格
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData} {@link DemoMergeData}
     * <p>
     * 2. 創建一個merge策略 並註冊
     * <p>
     * 3. 直接寫即可
     *
     * @since 2.2.0-beta1
     */
    @Test
    public void mergeWrite() {
        // 方法1 註解
        String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        // 在DemoStyleData裏面加上ContentLoopMerge註解
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, DemoMergeData.class).sheet("模板").doWrite(data());

        // 方法2 自定義合併單元格策略
        fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
        // 每隔2行會合並 把eachColumn 設置成 3 也就是我們數據的長度,所以就第一列會合並。當然其他合併策略也可以自己寫
        LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data());
    }

    /**
     * 使用table去寫入
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 然後寫入table即可
     */
    @Test
    public void tableWrite() {
        String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏直接寫多個table的案例了,如果只有一個 也可以直一行代碼搞定,參照其他案例
        // 這裏 需要指定寫用哪個class去寫
        ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
        // 把sheet設置爲不需要頭 不然會輸出sheet的頭 這樣看起來第一個table 就有2個頭了
        WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build();
        // 這裏必須指定需要頭,table 會繼承sheet的配置,sheet配置了不需要,table 默認也是不需要
        WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build();
        WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build();
        // 第一次寫入會創建頭
        excelWriter.write(data(), writeSheet, writeTable0);
        // 第二次寫如也會創建頭,然後在第一次的後面寫入數據
        excelWriter.write(data(), writeSheet, writeTable1);
        /// 千萬別忘記finish 會幫忙關閉流
        excelWriter.finish();
    }

    /**
     * 動態頭,實時生成頭寫入
     * <p>
     * 思路是這樣子的,先創建List<String>頭格式的sheet僅僅寫入頭,然後通過table 不寫入頭的方式 去寫入數據
     *
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 然後寫入table即可
     */
    @Test
    public void dynamicHeadWrite() {
        String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";
        EasyExcel.write(fileName)
            // 這裏放入動態頭
            .head(head()).sheet("模板")
            // 當然這裏數據也可以用 List<List<String>> 去傳入
            .doWrite(data());
    }

    /**
     * 自動列寬(不太精確)
     * <p>
     * 這個目前不是很好用,比如有數字就會導致換行。而且長度也不是剛好和實際長度一致。 所以需要精確到剛好列寬的慎用。 當然也可以自己參照
     * {@link LongestMatchColumnWidthStyleStrategy}重新實現.
     * <p>
     * poi 自帶{@link SXSSFSheet#autoSizeColumn(int)} 對中文支持也不太好。目前沒找到很好的算法。 有的話可以推薦下。
     *
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link LongestMatchColumnWidthData}
     * <p>
     * 2. 註冊策略{@link LongestMatchColumnWidthStyleStrategy}
     * <p>
     * 3. 直接寫即可
     */
    @Test
    public void longestMatchColumnWidthWrite() {
        String fileName =
            TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, LongestMatchColumnWidthData.class)
            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong());
    }

    /**
     * 下拉,超鏈接等自定義攔截器(上面幾點都不符合但是要對單元格進行操作的參照這個)
     * <p>
     * demo這裏實現2點。1. 對第一行第一列的頭超鏈接到:https://github.com/alibaba/easyexcel 2. 對第一列第一行和第二行的數據新增下拉框,顯示 測試1 測試2
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 註冊攔截器 {@link CustomCellWriteHandler} {@link CustomSheetWriteHandler}
     * <p>
     * 2. 直接寫即可
     */
    @Test
    public void customHandlerWrite() {
        String fileName = TestFileUtil.getPath() + "customHandlerWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new CustomSheetWriteHandler())
            .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data());
    }

    /**
     * 插入批註
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link DemoData}
     * <p>
     * 2. 註冊攔截器 {@link CommentWriteHandler}
     * <p>
     * 2. 直接寫即可
     */
    @Test
    public void commentWrite() {
        String fileName = TestFileUtil.getPath() + "commentWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        // 這裏要注意inMemory 要設置爲true,才能支持批註。目前沒有好的辦法解決 不在內存處理批註。這個需要自己選擇。
        EasyExcel.write(fileName, DemoData.class).inMemory(Boolean.TRUE).registerWriteHandler(new CommentWriteHandler())
            .sheet("模板").doWrite(data());
    }

    /**
     * 可變標題處理(包括標題國際化等)
     * <p>
     * 簡單的說用List<List<String>>的標題 但是還支持註解
     * <p>
     * 1. 創建excel對應的實體對象 參照{@link ConverterData}
     * <p>
     * 2. 直接寫即可
     */
    @Test
    public void variableTitleWrite() {
        // 寫法1
        String fileName = TestFileUtil.getPath() + "variableTitleWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName, ConverterData.class).head(variableTitleHead()).sheet("模板").doWrite(data());
    }

    /**
     * 不創建對象的寫
     */
    @Test
    public void noModelWrite() {
        // 寫法1
        String fileName = TestFileUtil.getPath() + "noModelWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(fileName).head(head()).sheet("模板").doWrite(dataList());
    }

    private List<LongestMatchColumnWidthData> dataLong() {
        List<LongestMatchColumnWidthData> list = new ArrayList<LongestMatchColumnWidthData>();
        for (int i = 0; i < 10; i++) {
            LongestMatchColumnWidthData data = new LongestMatchColumnWidthData();
            data.setString("測試很長的字符串測試很長的字符串測試很長的字符串" + i);
            data.setDate(new Date());
            data.setDoubleData(1000000000000.0);
            list.add(data);
        }
        return list;
    }

    private List<List<String>> variableTitleHead() {
        List<List<String>> list = new ArrayList<List<String>>();
        List<String> head0 = new ArrayList<String>();
        head0.add("string" + System.currentTimeMillis());
        List<String> head1 = new ArrayList<String>();
        head1.add("number" + System.currentTimeMillis());
        List<String> head2 = new ArrayList<String>();
        head2.add("date" + System.currentTimeMillis());
        list.add(head0);
        list.add(head1);
        list.add(head2);
        return list;
    }

    private List<List<String>> head() {
        List<List<String>> list = new ArrayList<List<String>>();
        List<String> head0 = new ArrayList<String>();
        head0.add("字符串" + System.currentTimeMillis());
        List<String> head1 = new ArrayList<String>();
        head1.add("數字" + System.currentTimeMillis());
        List<String> head2 = new ArrayList<String>();
        head2.add("日期" + System.currentTimeMillis());
        list.add(head0);
        list.add(head1);
        list.add(head2);
        return list;
    }

    private List<List<Object>> dataList() {
        List<List<Object>> list = new ArrayList<List<Object>>();
        for (int i = 0; i < 10; i++) {
            List<Object> data = new ArrayList<Object>();
            data.add("字符串" + i);
            data.add(new Date());
            data.add(0.56);
            list.add(data);
        }
        return list;
    }

    private List<DemoData> data() {
        List<DemoData> list = new ArrayList<DemoData>();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字符串" + i);
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章