好用的EasyExcel工具類(2.1.6版本)


寫在前面

EasyExcel是阿里推出的一款高性能的開源excel讀寫框架,由於2.0.5之后的版本變動比較大,很多以前的接口都被廢棄了,故筆者整理了一個適用較高版本的工具類,方便自己使用。實際主要是懶得記對應的API,並且匹配自己平時的編程習慣。有需要的小伙伴自取。

easyexcel開源地址:https://github.com/alibaba/easyexcel

引入依賴

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

工具類

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author jwhappy
 * @date 2020/4/22
 */
public class EasyExcelUtil
{
    /**
     * 同步無模型讀(默認讀取sheet0,從第2行開始讀)
     * @param filePath
     * @return
     */
    public static List<Map<Integer, String>> syncRead(String filePath){
        return EasyExcelFactory.read(filePath).sheet().doReadSync();
    }

    /**
     * 同步無模型讀(默認表頭占一行,從第2行開始讀)
     * @param filePath
     * @param sheetNo sheet頁號,從0開始
     * @return
     */
    public static List<Map<Integer, String>> syncRead(String filePath, Integer sheetNo){
        return EasyExcelFactory.read(filePath).sheet(sheetNo).doReadSync();
    }

    /**
     * 同步無模型讀(指定sheet和表頭占的行數)
     * @param inputStream
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return List<Map<colNum, cellValue>>
     */
    public static List<Map<Integer, String>> syncRead(InputStream inputStream, Integer sheetNo, Integer headRowNum){
        return EasyExcelFactory.read(inputStream).sheet(sheetNo).headRowNumber(headRowNum).doReadSync();
    }

    /**
     * 同步無模型讀(指定sheet和表頭占的行數)
     * @param file
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return List<Map<colNum, cellValue>>
     */
    public static List<Map<Integer, String>> syncRead(File file, Integer sheetNo, Integer headRowNum){
        return EasyExcelFactory.read(file).sheet(sheetNo).headRowNumber(headRowNum).doReadSync();
    }

    /**
     * 同步無模型讀(指定sheet和表頭占的行數)
     * @param filePath
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return List<Map<colNum, cellValue>>
     */
    public static List<Map<Integer, String>> syncRead(String filePath, Integer sheetNo, Integer headRowNum){
        return EasyExcelFactory.read(filePath).sheet(sheetNo).headRowNumber(headRowNum).doReadSync();
    }

    /**
     * 同步按模型讀(默認讀取sheet0,從第2行開始讀)
     * @param filePath
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @return
     */
    public static List<T> syncReadModel(String filePath, Class clazz){
        return EasyExcelFactory.read(filePath).sheet().head(clazz).doReadSync();
    }

    /**
     * 同步按模型讀(默認表頭占一行,從第2行開始讀)
     * @param filePath
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo sheet頁號,從0開始
     * @return
     */
    public static List<T> syncReadModel(String filePath, Class clazz, Integer sheetNo){
        return EasyExcelFactory.read(filePath).sheet(sheetNo).head(clazz).doReadSync();
    }

    /**
     * 同步按模型讀(指定sheet和表頭占的行數)
     * @param inputStream
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return
     */
    public static List<T> syncReadModel(InputStream inputStream, Class clazz, Integer sheetNo, Integer headRowNum){
        return EasyExcelFactory.read(inputStream).sheet(sheetNo).headRowNumber(headRowNum).head(clazz).doReadSync();
    }

    /**
     * 同步按模型讀(指定sheet和表頭占的行數)
     * @param file
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return
     */
    public static List<T> syncReadModel(File file, Class clazz, Integer sheetNo, Integer headRowNum){
        return EasyExcelFactory.read(file).sheet(sheetNo).headRowNumber(headRowNum).head(clazz).doReadSync();
    }

    /**
     * 同步按模型讀(指定sheet和表頭占的行數)
     * @param filePath
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return
     */
    public static List<T> syncReadModel(String filePath, Class clazz, Integer sheetNo, Integer headRowNum){
        return EasyExcelFactory.read(filePath).sheet(sheetNo).headRowNumber(headRowNum).head(clazz).doReadSync();
    }

    /**
     * 異步無模型讀(默認讀取sheet0,從第2行開始讀)
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param filePath 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return
     */
    public static void asyncRead(String filePath, AnalysisEventListener<T> excelListener){
        EasyExcelFactory.read(filePath, excelListener).sheet().doRead();
    }

    /**
     * 異步無模型讀(默認表頭占一行,從第2行開始讀)
     * @param filePath 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param sheetNo sheet頁號,從0開始
     * @return
     */
    public static void asyncRead(String filePath, AnalysisEventListener<T> excelListener, Integer sheetNo){
        EasyExcelFactory.read(filePath, excelListener).sheet(sheetNo).doRead();
    }

    /**
     * 異步無模型讀(指定sheet和表頭占的行數)
     * @param inputStream
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return
     */
    public static void asyncRead(InputStream inputStream, AnalysisEventListener<T> excelListener, Integer sheetNo, Integer headRowNum){
        EasyExcelFactory.read(inputStream, excelListener).sheet(sheetNo).headRowNumber(headRowNum).doRead();
    }

    /**
     * 異步無模型讀(指定sheet和表頭占的行數)
     * @param file
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return
     */
    public static void asyncRead(File file, AnalysisEventListener<T> excelListener, Integer sheetNo, Integer headRowNum){
        EasyExcelFactory.read(file, excelListener).sheet(sheetNo).headRowNumber(headRowNum).doRead();
    }

    /**
     * 異步無模型讀(指定sheet和表頭占的行數)
     * @param filePath
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param sheetNo sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     * @return
     */
    public static void asyncRead(String filePath, AnalysisEventListener<T> excelListener, Integer sheetNo, Integer headRowNum){
        EasyExcelFactory.read(filePath, excelListener).sheet(sheetNo).headRowNumber(headRowNum).doRead();
    }

    /**
     * 異步按模型讀取(默認讀取sheet0,從第2行開始讀)
     * @param filePath
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     */
    public static void asyncReadModel(String filePath, AnalysisEventListener<T> excelListener, Class clazz){
        EasyExcelFactory.read(filePath, clazz, excelListener).sheet().doRead();
    }

    /**
     * 異步按模型讀取(默認表頭占一行,從第2行開始讀)
     * @param filePath
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo  sheet頁號,從0開始
     */
    public static void asyncReadModel(String filePath, AnalysisEventListener<T> excelListener, Class clazz, Integer sheetNo){
        EasyExcelFactory.read(filePath, clazz, excelListener).sheet(sheetNo).doRead();
    }

    /**
     * 異步按模型讀取
     * @param inputStream
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo  sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     */
    public static void asyncReadModel(InputStream inputStream, AnalysisEventListener<T> excelListener, Class clazz, Integer sheetNo, Integer headRowNum){
        EasyExcelFactory.read(inputStream, clazz, excelListener).sheet(sheetNo).headRowNumber(headRowNum).doRead();
    }

    /**
     * 異步按模型讀取
     * @param file
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo  sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     */
    public static void asyncReadModel(File file, AnalysisEventListener<T> excelListener, Class clazz, Integer sheetNo, Integer headRowNum){
        EasyExcelFactory.read(file, clazz, excelListener).sheet(sheetNo).headRowNumber(headRowNum).doRead();
    }

    /**
     * 異步按模型讀取
     * @param filePath
     * @param excelListener 監聽器,在監聽器中可以處理行數據LinkedHashMap,表頭數據,異常處理等
     * @param clazz 模型的類類型(excel數據會按該類型轉換成對象)
     * @param sheetNo  sheet頁號,從0開始
     * @param headRowNum 表頭占的行數,從0開始(如果要連表頭一起讀出來則傳0)
     */
    public static void asyncReadModel(String filePath, AnalysisEventListener<T> excelListener, Class clazz, Integer sheetNo, Integer headRowNum){
        EasyExcelFactory.read(filePath, clazz, excelListener).sheet(sheetNo).headRowNumber(headRowNum).doRead();
    }

    /**
     * 無模板寫文件
     * @param filePath
     * @param head 表頭數據
     * @param data 表內容數據
     */
    public static void write(String filePath, List<List<String>> head, List<List<Object>> data){
        EasyExcel.write(filePath).head(head).sheet().doWrite(data);
    }

    /**
     * 無模板寫文件
     * @param filePath
     * @param head 表頭數據
     * @param data 表內容數據
     * @param sheetNo sheet頁號,從0開始
     * @param sheetName sheet名稱
     */
    public static void write(String filePath, List<List<String>> head, List<List<Object>> data, Integer sheetNo, String sheetName){
        EasyExcel.write(filePath).head(head).sheet(sheetNo, sheetName).doWrite(data);
    }

    /**
     * 根據excel模板文件寫入文件
     * @param filePath
     * @param templateFileName
     * @param headClazz
     * @param data
     */
    public static void writeTemplate(String filePath, String templateFileName, Class headClazz, List data){
        EasyExcel.write(filePath, headClazz).withTemplate(templateFileName).sheet().doWrite(data);
    }

    /**
     * 根據excel模板文件寫入文件
     * @param filePath
     * @param templateFileName
     * @param data
     */
    public static void writeTemplate(String filePath, String templateFileName, List data){
        EasyExcel.write(filePath).withTemplate(templateFileName).sheet().doWrite(data);
    }

    /**
     * 按模板寫文件
     * @param filePath
     * @param headClazz 表頭模板
     * @param data 數據
     */
    public static void write(String filePath, Class headClazz, List data){
        EasyExcel.write(filePath, headClazz).sheet().doWrite(data);
    }

    /**
     * 按模板寫文件
     * @param filePath
     * @param headClazz 表頭模板
     * @param data 數據
     * @param sheetNo sheet頁號,從0開始
     * @param sheetName sheet名稱
     */
    public static void write(String filePath, Class headClazz, List data, Integer sheetNo, String sheetName){
        EasyExcel.write(filePath, headClazz).sheet(sheetNo, sheetName).doWrite(data);
    }

    /**
     * 按模板寫文件
     * @param filePath
     * @param headClazz 表頭模板
     * @param data 數據
     * @param writeHandler 自定義的處理器,比如設置table樣式,設置超鏈接、單元格下拉框等等功能都可以通過這個實現(需要注冊多個則自己通過鏈式去調用)
     * @param sheetNo sheet頁號,從0開始
     * @param sheetName sheet名稱
     */
    public static void write(String filePath, Class headClazz, List data, WriteHandler writeHandler, Integer sheetNo, String sheetName){
        EasyExcel.write(filePath, headClazz).registerWriteHandler(writeHandler).sheet(sheetNo, sheetName).doWrite(data);
    }

    /**
     * 按模板寫文件(包含某些字段)
     * @param filePath
     * @param headClazz 表頭模板
     * @param data 數據
     * @param includeCols 過濾包含的字段,根據字段名稱過濾
     * @param sheetNo sheet頁號,從0開始
     * @param sheetName sheet名稱
     */
    public static void writeInclude(String filePath, Class headClazz, List data, Set<String> includeCols, Integer sheetNo, String sheetName){
        EasyExcel.write(filePath, headClazz).includeColumnFiledNames(includeCols).sheet(sheetNo, sheetName).doWrite(data);
    }

    /**
     * 按模板寫文件(排除某些字段)
     * @param filePath
     * @param headClazz 表頭模板
     * @param data 數據
     * @param excludeCols 過濾排除的字段,根據字段名稱過濾
     * @param sheetNo sheet頁號,從0開始
     * @param sheetName sheet名稱
     */
    public static void writeExclude(String filePath, Class headClazz, List data, Set<String> excludeCols, Integer sheetNo, String sheetName){
        EasyExcel.write(filePath, headClazz).excludeColumnFiledNames(excludeCols).sheet(sheetNo, sheetName).doWrite(data);
    }

    /**
     * 多個sheet頁的數據鏈式寫入
     * ExcelUtil.writeWithSheets(outputStream)
     *                 .writeModel(ExcelModel.class, excelModelList, "sheetName1")
     *                 .write(headData, data,"sheetName2")
     *                 .finish();
     * @param outputStream
     * @return
     */
    public static EasyExcelWriterFactory writeWithSheets(OutputStream outputStream){
        EasyExcelWriterFactory excelWriter = new EasyExcelWriterFactory(outputStream);
        return excelWriter;
    }

    /**
     * 多個sheet頁的數據鏈式寫入
     * ExcelUtil.writeWithSheets(file)
     *                 .writeModel(ExcelModel.class, excelModelList, "sheetName1")
     *                 .write(headData, data,"sheetName2")
     *                 .finish();
     * @param file
     * @return
     */
    public static EasyExcelWriterFactory writeWithSheets(File file){
        EasyExcelWriterFactory excelWriter = new EasyExcelWriterFactory(file);
        return excelWriter;
    }

    /**
     * 多個sheet頁的數據鏈式寫入
     * ExcelUtil.writeWithSheets(filePath)
     *                 .writeModel(ExcelModel.class, excelModelList, "sheetName1")
     *                 .write(headData, data,"sheetName2")
     *                 .finish();
     * @param filePath
     * @return
     */
    public static EasyExcelWriterFactory writeWithSheets(String filePath){
        EasyExcelWriterFactory excelWriter = new EasyExcelWriterFactory(filePath);
        return excelWriter;
    }

    /**
     * 多個sheet頁的數據鏈式寫入(失敗了會返回一個有部分數據的Excel)
     * ExcelUtil.writeWithSheets(response, exportFileName)
     *                 .writeModel(ExcelModel.class, excelModelList, "sheetName1")
     *                 .write(headData, data,"sheetName2")
     *                 .finish();
     * @param response
     * @param exportFileName 導出的文件名稱
     * @return
     */
    public static EasyExcelWriterFactory writeWithSheetsWeb(HttpServletResponse response, String exportFileName) throws IOException{
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 這里URLEncoder.encode可以防止中文亂碼
        String fileName = URLEncoder.encode(exportFileName, "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcelWriterFactory excelWriter = new EasyExcelWriterFactory(response.getOutputStream());
        return excelWriter;
    }
}

/**
 * 默認按模型讀取的監聽器
 * @param <T>
 */
@Slf4j
class DefaultExcelListener<T> extends AnalysisEventListener<T>
{
    private final List<T> rows = new ArrayList();

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        log.info("解析到一條頭數據:{}", JSON.toJSONString(headMap));
    }

    @Override
    public void invoke(T object, AnalysisContext context) {
        rows.add(object);
        // 實際數據量比較大時,rows里的數據可以存到一定量之后進行批量處理(比如存到數據庫),
        // 然后清空列表,以防止內存占用過多造成OOM
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("read {} rows", rows.size());
    }

    /**
     * 在轉換異常 獲取其他異常下會調用本接口。拋出異常則停止讀取。如果這里不拋出異常則 繼續讀取下一行。
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        log.error("解析失敗,但是繼續解析下一行:{}", exception.getMessage());
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
            log.error("第{}行,第{}列解析異常,數據為:{}", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
        }
    }

    public List<T> getRows() {
        return rows;
    }
}
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;

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

/**
 * 自定義EasyExcel寫工廠
 */
public class EasyExcelWriterFactory
{
    private int sheetNo = 0;
    private ExcelWriter excelWriter = null;

    public EasyExcelWriterFactory(OutputStream outputStream) {
        excelWriter = EasyExcel.write(outputStream).build();
    }

    public EasyExcelWriterFactory(File file) {
        excelWriter = EasyExcel.write(file).build();
    }

    public EasyExcelWriterFactory(String filePath) {
        excelWriter = EasyExcel.write(filePath).build();
    }

    /**
     * 鏈式模板表頭寫入
     * @param headClazz 表頭格式
     * @param data 數據 List<ExcelModel> 或者List<List<Object>>
     * @return
     */
    public EasyExcelWriterFactory writeModel(Class headClazz, List data, String sheetName){
        excelWriter.write(data, EasyExcel.writerSheet(this.sheetNo++, sheetName).head(headClazz).build());
        return this;
    }

    /**
     * 鏈式自定義表頭寫入
     * @param head
     * @param data 數據 List<ExcelModel> 或者List<List<Object>>
     * @param sheetName
     * @return
     */
    public EasyExcelWriterFactory write(List<List<String>> head, List data, String sheetName){
        excelWriter.write(data, EasyExcel.writerSheet(this.sheetNo++, sheetName).head(head).build());
        return this;
    }

    public void finish() {
        excelWriter.finish();
    }
}


免責聲明!

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



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