easyexcel讀取excel合并單元格數(shù)據(jù)的操作代碼
普通的excel列表,easyexcel讀取是沒有什么問題的。但是,如果有合并單元格,那么它讀取的時(shí)候,能獲取數(shù)據(jù),但是數(shù)據(jù)是不完整的。如下所示的單元格數(shù)據(jù):
我們通過簡單的異步讀取,最后查看數(shù)據(jù)內(nèi)容:
ExcelData.java
package com.example.model; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class ExcelData { @ExcelProperty("學(xué)生姓名") private String name; @ExcelProperty("年齡") private int age; @ExcelProperty("性別") private String gender; @ExcelProperty({"課程", "課程名稱"}) private String courseName; @ExcelProperty({"課程", "分?jǐn)?shù)"}) private double score; }
ExcelRead.java
package com.example.service; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.example.model.ExcelData; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; @Slf4j public class ExcelRead { private static final String FILEPATH = "e:\\test\\student.xlsx"; public List<ExcelData> list() { List<ExcelData> excelDataList = new ArrayList<>(); EasyExcel.read(FILEPATH, ExcelData.class, new AnalysisEventListener<ExcelData>() { @Override public void invoke(ExcelData excelData, AnalysisContext analysisContext) { log.info("read data {}", excelData); excelDataList.add(excelData); } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { } }).sheet().doRead(); return excelDataList; } }
ExcelTest.java
package com.example.service; import com.example.model.ExcelData; import java.util.List; public class ExcelTest { public static void main(String[] args) { ExcelRead excelRead = new ExcelRead(); List<ExcelData> list = excelRead.list(); System.out.println(list.size()); } }
運(yùn)行程序,打印日志信息如下:
獲取了6個(gè)數(shù)據(jù)沒錯(cuò),但是每一個(gè)合并單元格記錄里面都有一個(gè)數(shù)據(jù)獲取是空的。
解決辦法就是需要在異步讀取數(shù)據(jù)監(jiān)聽器里面讀取合并單元格的額外數(shù)據(jù),并把這部分?jǐn)?shù)據(jù)給補(bǔ)充上。
需要修改的地方:
1、實(shí)體需要增加注解索引值:
@Data @AllArgsConstructor @NoArgsConstructor public class ExcelData { @ExcelProperty(value = "學(xué)生姓名", index = 0) private String name; @ExcelProperty(value = "年齡", index = 1) private int age; @ExcelProperty(value = "性別", index = 2) private String gender; @ExcelProperty(value = {"課程", "課程名稱"}, index = 3) private String courseName; @ExcelProperty(value = {"課程", "分?jǐn)?shù)"}, index = 4) private double score; }
2、自定義監(jiān)聽器,讀取合并單元格數(shù)據(jù):
package com.example.service; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.CellExtra; import com.example.model.ExcelData; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; @Slf4j public class CustomAnalysisEventListener extends AnalysisEventListener<ExcelData> { private int headRowNum; public CustomAnalysisEventListener(int headRowNum) { this.headRowNum = headRowNum; } private List<ExcelData> list = new ArrayList<>(); private List<CellExtra> cellExtraList = new ArrayList<>(); @Override public void invoke(ExcelData excelData, AnalysisContext analysisContext) { log.info(" data -> {}", excelData); list.add(excelData); } @Override public void extra(CellExtra extra, AnalysisContext context) { CellExtraTypeEnum type = extra.getType(); switch (type) { case MERGE: { if (extra.getRowIndex() >= headRowNum) { cellExtraList.add(extra); } break; } default:{ } } } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { } public List<ExcelData> getList() { return list; } public List<CellExtra> getCellExtraList() { return cellExtraList; } }
3、通過監(jiān)聽器讀取數(shù)據(jù),通過監(jiān)聽器獲取數(shù)據(jù)和合并單元格數(shù)據(jù),然后設(shè)置單元格數(shù)據(jù)。
package com.example.service; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.metadata.CellExtra; import com.example.model.ExcelData; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; import java.util.List; @Slf4j public class ExcelRead { private static final int HEAD_ROW_NUM = 2; private static final String FILEPATH = "e:\\test\\student.xlsx"; public List<ExcelData> list() { List<ExcelData> excelDataList; CustomAnalysisEventListener listener = new CustomAnalysisEventListener(HEAD_ROW_NUM); EasyExcel.read(FILEPATH, ExcelData.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead(); excelDataList = listener.getList(); List<CellExtra> cellExtraList = listener.getCellExtraList(); if (cellExtraList != null && cellExtraList.size() > 0) { mergeExcelData(excelDataList, cellExtraList, HEAD_ROW_NUM); } return excelDataList; } private void mergeExcelData(List<ExcelData> excelDataList, List<CellExtra> cellExtraList, int headRowNum) { cellExtraList.forEach(cellExtra -> { int firstRowIndex = cellExtra.getFirstRowIndex() - headRowNum; int lastRowIndex = cellExtra.getLastRowIndex() - headRowNum; int firstColumnIndex = cellExtra.getFirstColumnIndex(); int lastColumnIndex = cellExtra.getLastColumnIndex(); //獲取初始值 Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, excelDataList); //設(shè)置值 for (int i = firstRowIndex; i <= lastRowIndex; i++) { for (int j = firstColumnIndex; j <= lastColumnIndex; j++) { setInitValueToList(initValue, i, j, excelDataList); } } }); } private void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<ExcelData> data) { ExcelData object = data.get(rowIndex); for (Field field : object.getClass().getDeclaredFields()) { field.setAccessible(true); ExcelProperty annotation = field.getAnnotation(ExcelProperty.class); if (annotation != null) { if (annotation.index() == columnIndex) { try { field.set(object, filedValue); break; } catch (IllegalAccessException e) { log.error("設(shè)置合并單元格的值異常:{}", e.getMessage()); } } } } } private Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<ExcelData> data) { Object filedValue = null; ExcelData object = data.get(firstRowIndex); for (Field field : object.getClass().getDeclaredFields()) { field.setAccessible(true); ExcelProperty annotation = field.getAnnotation(ExcelProperty.class); if (annotation != null) { if (annotation.index() == firstColumnIndex) { try { filedValue = field.get(object); break; } catch (IllegalAccessException e) { log.error("設(shè)置合并單元格的初始值異常:{}", e.getMessage()); } } } } return filedValue; } }
有個(gè)小細(xì)節(jié)需要注意,我們在通過監(jiān)聽器讀取的時(shí)候,還需要額外讀取合并單元格部分。
EasyExcel.read(FILEPATH, ExcelData.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
還有個(gè)小細(xì)節(jié),就是我們的表格一般都是有頭的,頭的內(nèi)容可能是2行,可能是1行,在進(jìn)行合并單元格處理的時(shí)候,需要考慮這個(gè)行數(shù)。我們定義了一個(gè)常量HEAD_ROW_NUM來記錄這個(gè)行數(shù),最后進(jìn)行單元格值計(jì)算的時(shí)候傳入。
我在處理excel數(shù)據(jù)中發(fā)現(xiàn),如果這個(gè)單元格合并,是由我們的程序自己做的,那么它讀取的時(shí)候,是沒有問題的。在上面為null的地方,它其實(shí)都有值:
但是在實(shí)際中,我們的excel不能保證不被人為編輯,那么就很有可能,我們在進(jìn)行合并單元格的時(shí)候,把有值和無值合并到一起,最后就出現(xiàn)前面提到的讀取合并單元格出現(xiàn)數(shù)據(jù)缺失的問題。 而我們期望,合并單元格部分他們的數(shù)據(jù)應(yīng)該是一樣的。所以今天的解決方案是一種保險(xiǎn)的做法,不管你的表格是否有合并單元格,是否人為修改,最終都能把合并單元格缺失的數(shù)據(jù)進(jìn)行恢復(fù)。
到此這篇關(guān)于easyexcel讀取excel合并單元格數(shù)據(jù)的操作代碼的文章就介紹到這了,更多相關(guān)easyexcel合并單元格數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot配置數(shù)據(jù)庫密碼加密的方法
由于系統(tǒng)安全的考慮,配置文件中不能出現(xiàn)明文密碼的問題,本文就給大家詳細(xì)介紹下springboot配置數(shù)據(jù)庫密碼加密的方法,下面話不多說了,來一起看看詳細(xì)的介紹吧,需要的朋友可以參考下2023-08-08Centos中yum方式安裝java的實(shí)現(xiàn)示例
這篇文章主要介紹了Centos中yum方式安裝java的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04IDEA 插件 mapper和xml互相跳轉(zhuǎn)操作
這篇文章主要介紹了IDEA 插件 mapper和xml互相跳轉(zhuǎn)操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02SpringBoot 多線程事務(wù)回滾的實(shí)現(xiàn)
本文是基于springboot的@Async注解開啟多線程,并通過自定義注解和AOP實(shí)現(xiàn)的多線程事務(wù),避免繁瑣的手動(dòng)提交/回滾事務(wù),感興趣的可以了解一下2024-02-02Spring的BeanFactoryPostProcessor接口示例代碼詳解
這篇文章主要介紹了Spring的BeanFactoryPostProcessor接口,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02