欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

EasyExcel工具讀取Excel空數(shù)據(jù)行問(wèn)題的解決辦法

 更新時(shí)間:2022年08月10日 15:30:41   作者:流沙QS  
EasyExcel是阿里巴巴開(kāi)源的一個(gè)excel處理框架,以使用簡(jiǎn)單,節(jié)省內(nèi)存著稱(chēng),下面這篇文章主要給大家介紹了關(guān)于EasyExcel工具讀取Excel空數(shù)據(jù)行問(wèn)題的解決辦法,需要的朋友可以參考下

EasyExcel是Alibaba開(kāi)源的一個(gè)Java處理Excel的工具。

官網(wǎng)解讀:快速、簡(jiǎn)潔、解決大文件內(nèi)存溢出的java處理Excel工具

快速

快速的讀取excel中的數(shù)據(jù)。

簡(jiǎn)潔

映射excel和實(shí)體類(lèi),讓代碼變的更加簡(jiǎn)潔。

大文件

在讀寫(xiě)大文件的時(shí)候使用磁盤(pán)做緩存,更加的節(jié)約內(nèi)存。

官網(wǎng)地址:https://easyexcel.opensource.alibaba.com/

感興趣可自己琢磨,該工具簡(jiǎn)單易上手,且性能相對(duì)比較高。

本文主要處理的問(wèn)題是該工具讀取Excel空數(shù)據(jù)行的問(wèn)題。

首先解釋為什么會(huì)產(chǎn)生空數(shù)據(jù)行:簡(jiǎn)單解釋就是你在Excel中設(shè)置了單元的樣式,卻沒(méi)有給單元格設(shè)值。因此,該工具在讀取數(shù)據(jù)時(shí)便沒(méi)有判斷這一步,直接讀取到整行數(shù)據(jù)均為null。

理解了核心問(wèn)題后,要解決這個(gè)問(wèn)題,實(shí)現(xiàn)思路也不難。

莫非就是把這種空數(shù)據(jù)行過(guò)濾即可。

本文是基于批處理監(jiān)聽(tīng)器實(shí)現(xiàn)數(shù)據(jù)讀取的,自定義集成該監(jiān)聽(tīng)器(com.alibaba.excel.read.listener.PageReadListener),實(shí)現(xiàn)自己的邏輯即可解決問(wèn)題。

下面是自定義監(jiān)聽(tīng)器

package xin.cosmos.basic.easyexcel.framework;
 
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;
import xin.cosmos.basic.util.ObjectsUtil;
 
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
 
/**
 * 自定義分批Excel數(shù)據(jù)讀取監(jiān)聽(tīng)器,解決官方無(wú)法移除空的Excel行問(wèn)題
 *
 * @param <T>
 * @author geng
 */
@Slf4j
public class BatchPageReadListener<T> extends PageReadListener<T> {
 
    /**
     * Temporary storage of data
     */
    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * consumer
     */
    private final Consumer<List<T>> consumer;
 
    public BatchPageReadListener(Consumer<List<T>> consumer) {
        super(consumer);
        this.consumer = consumer;
    }
 
    @Override
    public void invoke(T data, AnalysisContext context) {
        // 如果一行Excel數(shù)據(jù)均為空值,則不裝載該行數(shù)據(jù)
        if (isLineNullValue(data)) {
            return;
        }
        cachedDataList.add(data);
        if (cachedDataList.size() >= BATCH_COUNT) {
            consumer.accept(cachedDataList);
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }
 
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (ObjectsUtil.isNull(cachedDataList)) {
            return;
        }
        consumer.accept(cachedDataList);
    }
 
    /**
     * 判斷整行單元格數(shù)據(jù)是否均為空
     */
    private boolean isLineNullValue(T data) {
        if (data instanceof String) {
            return ObjectsUtil.isNull(data);
        }
        try {
            List<Field> fields = Arrays.stream(data.getClass().getDeclaredFields())
                    .filter(f -> f.isAnnotationPresent(ExcelProperty.class))
                    .collect(Collectors.toList());
            List<Boolean> lineNullList = new ArrayList<>(fields.size());
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(data);
                if (ObjectsUtil.isNull(value)) {
                    lineNullList.add(Boolean.TRUE);
                } else {
                    lineNullList.add(Boolean.FALSE);
                }
            }
            return lineNullList.stream().allMatch(Boolean.TRUE::equals);
        } catch (Exception e) {
            log.error("讀取數(shù)據(jù)行[{}]解析失敗: {}", data, e.getMessage());
        }
        return true;
    }
}

下面是我對(duì)EasyExcel封裝的工具類(lèi)

package xin.cosmos.basic.easyexcel.helper;
 
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import xin.cosmos.basic.define.ResultVO;
import xin.cosmos.basic.easyexcel.framework.BatchPageReadListener;
import xin.cosmos.basic.easyexcel.template.HeadVO;
import xin.cosmos.basic.exception.PlatformException;
import xin.cosmos.basic.util.BeanMapUtil;
import xin.cosmos.basic.util.ObjectsUtil;
 
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
 
/**
 * EasyExcel 幫助類(lèi)
 */
@Slf4j
public class EasyExcelHelper {
 
    /**
     * 讀取Excel文件
     *
     * @param stream      文件流
     * @param entityClass 讀取轉(zhuǎn)換的Java對(duì)象類(lèi)型
     * @param <T>
     * @return
     */
    public static <T> List<T> doReadExcelData(InputStream stream, Class<T> entityClass) {
        List<T> data = new LinkedList<>();
        EasyExcelFactory.read(stream, entityClass, new PageReadListener<T>(data::addAll)).sheet().doRead();
        return data;
    }
 
    /**
     * 讀取Excel文件
     *
     * @param stream      文件流
     * @param entityClass 讀取轉(zhuǎn)換的Java對(duì)象類(lèi)型
     * @param comparator  排序比較器
     * @param <T>
     * @return
     */
    public static <T> List<T> doReadExcelData(InputStream stream, Class<T> entityClass, Comparator<T> comparator) {
        List<T> data = new LinkedList<>();
        EasyExcelFactory.read(stream, entityClass, new BatchPageReadListener<T>(list -> {
            if (comparator != null) {
                list.sort(comparator);
            }
            data.addAll(list);
        })).sheet().doRead();
        return data;
    }
 
    /**
     * 讀取Excel文件
     *
     * @param file        MultipartFile文件
     * @param entityClass 讀取轉(zhuǎn)換的Java對(duì)象類(lèi)型
     */
    @SneakyThrows
    public static <T> List<T> doReadExcelData(MultipartFile file, Class<T> entityClass) {
        return doReadExcelData(file.getInputStream(), entityClass);
    }
 
    /**
     * 讀取Excel文件
     *
     * @param file        File文件
     * @param entityClass 讀取轉(zhuǎn)換的Java對(duì)象類(lèi)型
     */
    @SneakyThrows
    public static <T> List<T> doReadExcelData(File file, Class<T> entityClass) {
        List<T> data = new LinkedList<>();
        EasyExcelFactory.read(file, entityClass, new BatchPageReadListener<T>(data::addAll)).sheet().doRead();
        return data;
    }
 
    /**
     * Excel數(shù)據(jù)瀏覽器下載
     *
     * @param pathName    下載文件的完整路徑名稱(chēng)
     * @param data        需下載數(shù)據(jù)
     * @param entityClazz 下載數(shù)據(jù)類(lèi)型模板
     */
    @SneakyThrows
    public static <T> void downloadExcel(String pathName, List<T> data, Class<T> entityClazz) {
        try {
            // 構(gòu)建Excel表頭及數(shù)據(jù)體
            ExcelWriterSheetBuilder builder = EasyExcel.write(pathName)
                    .autoCloseStream(true)
                    .sheet("sheet1");
            doWriteWithDynamicColumns(builder, entityClazz, data);
        } catch (Exception e) {
            log.error("寫(xiě)文件錯(cuò)誤:{}", e.getMessage());
            throw new PlatformException("Excel下載數(shù)據(jù)錯(cuò)誤");
        }
    }
 
 
    /**
     * Excel數(shù)據(jù)瀏覽器下載
     * <p>
     * 前端下載js代碼示例:
     * <pre>
     * function downloadFile(bytes, fileName) {
     *    const blob = new Blob([bytes], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
     *    if (window.navigator.msSaveOrOpenBlob) { // 兼容IE10
     *          navigator.msSaveBlob(blob, fileName)
     *    } else {
     *         const url = window.URL.createObjectURL(blob);
     *         const a = document.createElement('a');
     *         a.href = url;
     *         a.download = fileName;
     *         a.click();
     *         window.URL.revokeObjectURL(url);
     *    }
     * }
     * </pre>
     *
     * @param excelFileName 下載文件名稱(chēng)
     * @param response      響應(yīng)容器
     * @param data          需下載數(shù)據(jù)
     * @param entityClazz   下載數(shù)據(jù)Bean實(shí)體類(lèi)型,蘇醒必須使用注解<code>@ExcelProperty</code>中value指定寫(xiě)出列的表頭嗎,名稱(chēng)
     */
    public static <T> void downloadExcelToResponse(HttpServletResponse response, String excelFileName, List<T> data, Class<T> entityClazz) {
        if (ObjectsUtil.isNull(data)) {
            log.error("寫(xiě)文件錯(cuò)誤:{}", "暫無(wú)可下載的數(shù)據(jù)");
            writeErrMsg(response, "暫無(wú)可下載的數(shù)據(jù)");
            return;
        }
        try {
            // 這里注意 有同學(xué)反應(yīng)使用swagger 會(huì)導(dǎo)致各種問(wèn)題,請(qǐng)直接用瀏覽器或者用postman
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            if (excelFileName.endsWith(".xlsx") || excelFileName.endsWith(".xls") ||
                    excelFileName.endsWith(".XLSX") || excelFileName.endsWith(".XLS")) {
                excelFileName = excelFileName.substring(0, excelFileName.lastIndexOf("."));
            }
            // 這里URLEncoder.encode可以防止中文亂碼 當(dāng)然和easy excel沒(méi)有關(guān)系
            String urlFileName = URLEncoder.encode(excelFileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + urlFileName + ".xlsx");
            response.setHeader("excel-file-name", urlFileName + ".xlsx");
 
            // 構(gòu)建Excel表頭及數(shù)據(jù)體
            ExcelWriterSheetBuilder builder = EasyExcel.write(response.getOutputStream())
                    .excelType(ExcelTypeEnum.XLSX)
                    .autoCloseStream(true)
                    .sheet("sheet1");
            doWriteWithDynamicColumns(builder, entityClazz, data);
        } catch (Exception e) {
            log.error("寫(xiě)文件錯(cuò)誤:{}", e.getMessage());
            writeErrMsg(response, e.getMessage());
        }
    }
 
 
    /**
     * EasyExcel支持動(dòng)態(tài)列寫(xiě)數(shù)據(jù)
     *
     * @param builder     指定輸出方式和樣式
     * @param entityClazz 實(shí)體的Class對(duì)象
     * @param data        Excel行數(shù)據(jù)
     */
    public static <T> void doWriteWithDynamicColumns(ExcelWriterSheetBuilder builder, Class<T> entityClazz, List<T> data) {
        List<HeadVO> customizeHeads = new ArrayList<>();
        Field[] fieldArray = entityClazz.getDeclaredFields();
        // 獲取類(lèi)的注解
        for (Field field : fieldArray) {
            // 忽略導(dǎo)出屬性
            if (field.isAnnotationPresent(ExcelIgnore.class)) {
                continue;
            }
            if (field.isAnnotationPresent(ExcelProperty.class)) {
                ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
                List<String> head = Arrays.asList(excelProperty.value());
                int index = excelProperty.index();
                int order = excelProperty.order();
                HeadVO headVO = HeadVO.builder().headTitle(head).index(index).order(order).field(field.getName()).build();
                customizeHeads.add(headVO);
            }
        }
 
        // 表頭排序
        Collections.sort(customizeHeads);
 
        // 處理表頭
        List<List<String>> heads = new ArrayList<>();
        List<String> fields = new ArrayList<>();
        for (int i = 0; i <= customizeHeads.size() - 1; i++) {
            heads.add(customizeHeads.get(i).getHeadTitle());
            fields.add(customizeHeads.get(i).getField());
        }
 
        // 處理數(shù)據(jù)
        List<List<Object>> objs = new ArrayList<>();
        List<Map<String, ?>> maps = BeanMapUtil.beansToMaps(data);
        maps.forEach(map -> {
            List<Object> obj = new ArrayList<>();
            for (String field : fields) {
                obj.add(map.get(field));
            }
            objs.add(obj);
        });
        builder.head(heads).doWrite(objs);
    }
 
 
    @SneakyThrows
    private static void writeErrMsg(HttpServletResponse response, String errMsg) {
        // 重置response
        response.reset();
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().println(JSON.toJSONString(ResultVO.failed(errMsg)));
    }
}
package xin.cosmos.basic.easyexcel.template;
 
import lombok.Builder;
import lombok.Data;
 
import java.util.List;
 
/**
 * EasyExcel 表頭信息VO類(lèi)
 */
@Builder
@Data
public class HeadVO implements Comparable<HeadVO> {
 
    /**
     * Excel表頭名稱(chēng)
     */
    private List<String> headTitle;
    /**
     * Excel表頭名稱(chēng)映射的Java對(duì)象屬性名稱(chēng)
     */
    private String field;
    /**
     * 主排序
     */
    private int index;
    /**
     * 次排序
     */
    private int order;
 
    /**
     * 升序排序
     * @param o
     * @return
     */
    @Override
    public int compareTo(HeadVO o) {
        if (this.index == o.getIndex()) {
            return this.order - o.getOrder();
        }
        return this.index - o.getIndex();
    }
}

最后是一個(gè)基于Spring cglib的Map<==>Java Bean之間的轉(zhuǎn)換工具

package xin.cosmos.basic.util;
 
import org.springframework.cglib.beans.BeanMap;
import xin.cosmos.basic.exception.PlatformException;
 
import java.util.*;
 
/**
 * bean和map互轉(zhuǎn) 工具類(lèi)
 * <p>
 * 使用到spring的cglib
 */
public class BeanMapUtil {
 
    /**
     * 將Bean轉(zhuǎn)為Map
     *
     * @param bean
     * @param <T>
     * @return
     */
    public static <T> Map<String, ?> beanToMap(T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        Map<String, Object> map = new HashMap<>();
        beanMap.forEach((key, value) -> map.put(String.valueOf(key), value));
        return map;
    }
 
    /**
     * 將Map轉(zhuǎn)為Bean
     *
     * @param map
     * @param beanClazz
     * @param <T>
     * @return
     */
    public static <T> T mapToBean(Map<String, ?> map, Class<T> beanClazz) {
        T bean;
        try {
            bean = beanClazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
            throw new PlatformException("Map集合轉(zhuǎn)換到Bean失敗");
        }
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }
 
    /**
     * 將一組Beans轉(zhuǎn)為L(zhǎng)ist
     *
     * @param dataList
     * @param <T>
     * @return
     */
    public static <T> List<Map<String, ?>> beansToMaps(List<T> dataList) {
        List<Map<String, ?>> list = new ArrayList<>();
        if (ObjectsUtil.isNull(dataList)) {
            return Collections.emptyList();
        }
        Map<String, ?> map;
        T bean;
        for (T t : dataList) {
            bean = t;
            map = beanToMap(bean);
            list.add(map);
        }
        return list;
    }
 
    /**
     * 將一組Map轉(zhuǎn)為一組Beans
     *
     * @param dataMaps
     * @param beanClazz
     * @param <T>
     * @return
     */
    public static <T> List<T> mapsToBeans(List<Map<String, ?>> dataMaps, Class<T> beanClazz) {
        List<T> list = new ArrayList<>();
        if (ObjectsUtil.isNull(dataMaps)) {
            return Collections.emptyList();
        }
        Map<String, ?> map;
        for (Map<String, ?> dataMap : dataMaps) {
            map = dataMap;
            T bean = mapToBean(map, beanClazz);
            list.add(bean);
        }
        return list;
    }
}
 

總結(jié)

到此這篇關(guān)于EasyExcel工具讀取Excel空數(shù)據(jù)行問(wèn)題解決的文章就介紹到這了,更多相關(guān)EasyExcel讀取Excel空數(shù)據(jù)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java編寫(xiě)計(jì)算器的常見(jiàn)方法實(shí)例總結(jié)

    Java編寫(xiě)計(jì)算器的常見(jiàn)方法實(shí)例總結(jié)

    這篇文章主要介紹了Java編寫(xiě)計(jì)算器的常見(jiàn)方法,結(jié)合實(shí)例形式總結(jié)分析了Java實(shí)現(xiàn)計(jì)算器功能的常用方法,需要的朋友可以參考下
    2016-04-04
  • 基于java中byte數(shù)組與int類(lèi)型的轉(zhuǎn)換(兩種方法)

    基于java中byte數(shù)組與int類(lèi)型的轉(zhuǎn)換(兩種方法)

    下面小編就為大家?guī)?lái)一篇基于java中byte數(shù)組與int類(lèi)型的轉(zhuǎn)換(兩種方法)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • 基于Java實(shí)現(xiàn)遍歷文件目錄并去除中文文件名

    基于Java實(shí)現(xiàn)遍歷文件目錄并去除中文文件名

    這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)遍歷文件目錄并去除中文文件名,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下
    2024-03-03
  • Java使用jdbc連接MySQL數(shù)據(jù)庫(kù)實(shí)例分析

    Java使用jdbc連接MySQL數(shù)據(jù)庫(kù)實(shí)例分析

    這篇文章主要介紹了Java使用jdbc連接MySQL數(shù)據(jù)庫(kù),結(jié)合實(shí)例形式分析了Java基于jdbc鏈接mysql的相關(guān)配置及工具類(lèi)的定義相關(guān)操作技巧,需要的朋友可以參考下
    2018-07-07
  • Json在Struts中的轉(zhuǎn)換與傳遞方法

    Json在Struts中的轉(zhuǎn)換與傳遞方法

    下面小編就為大家?guī)?lái)一篇Json在Struts中的轉(zhuǎn)換與傳遞方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11
  • springCloud gateWay 統(tǒng)一鑒權(quán)的實(shí)現(xiàn)代碼

    springCloud gateWay 統(tǒng)一鑒權(quán)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了springCloud gateWay 統(tǒng)一鑒權(quán)的實(shí)現(xiàn)代碼,統(tǒng)一鑒權(quán)包括鑒權(quán)邏輯和代碼實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-02-02
  • Java操作hdfs文件系統(tǒng)過(guò)程

    Java操作hdfs文件系統(tǒng)過(guò)程

    這篇文章主要介紹了Java操作hdfs文件系統(tǒng)過(guò)程,這個(gè)過(guò)程需要前置準(zhǔn)備默認(rèn)服務(wù)器上的hadoop服務(wù)已經(jīng)啟動(dòng)、本地如果是windows環(huán)境,需要本地配置下hadoop的環(huán)境變量,下面來(lái)看看具體得操作過(guò)程吧
    2022-02-02
  • 關(guān)于feign接口動(dòng)態(tài)代理源碼解析

    關(guān)于feign接口動(dòng)態(tài)代理源碼解析

    這篇文章主要介紹了關(guān)于feign接口動(dòng)態(tài)代理源碼解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Maven setting.xml配置文件詳解

    Maven setting.xml配置文件詳解

    本篇文章主要介紹了Maven setting.xml 配置文件詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • mybatis如何使用注解實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)查詢(xún)

    mybatis如何使用注解實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)查詢(xún)

    這篇文章主要介紹了mybatis如何使用注解實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)查詢(xún)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評(píng)論