easyexcel讀取excel合并單元格數據的操作代碼
普通的excel列表,easyexcel讀取是沒有什么問題的。但是,如果有合并單元格,那么它讀取的時候,能獲取數據,但是數據是不完整的。如下所示的單元格數據:

我們通過簡單的異步讀取,最后查看數據內容:
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("學生姓名")
private String name;
@ExcelProperty("年齡")
private int age;
@ExcelProperty("性別")
private String gender;
@ExcelProperty({"課程", "課程名稱"})
private String courseName;
@ExcelProperty({"課程", "分數"})
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());
}
}運行程序,打印日志信息如下:

獲取了6個數據沒錯,但是每一個合并單元格記錄里面都有一個數據獲取是空的。
解決辦法就是需要在異步讀取數據監(jiān)聽器里面讀取合并單元格的額外數據,并把這部分數據給補充上。
需要修改的地方:
1、實體需要增加注解索引值:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExcelData {
@ExcelProperty(value = "學生姓名", 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 = {"課程", "分數"}, index = 4)
private double score;
}2、自定義監(jiān)聽器,讀取合并單元格數據:
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)聽器讀取數據,通過監(jiān)聽器獲取數據和合并單元格數據,然后設置單元格數據。
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);
//設置值
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("設置合并單元格的值異常:{}", 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("設置合并單元格的初始值異常:{}", e.getMessage());
}
}
}
}
return filedValue;
}
}有個小細節(jié)需要注意,我們在通過監(jiān)聽器讀取的時候,還需要額外讀取合并單元格部分。
EasyExcel.read(FILEPATH, ExcelData.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
還有個小細節(jié),就是我們的表格一般都是有頭的,頭的內容可能是2行,可能是1行,在進行合并單元格處理的時候,需要考慮這個行數。我們定義了一個常量HEAD_ROW_NUM來記錄這個行數,最后進行單元格值計算的時候傳入。
我在處理excel數據中發(fā)現,如果這個單元格合并,是由我們的程序自己做的,那么它讀取的時候,是沒有問題的。在上面為null的地方,它其實都有值:

但是在實際中,我們的excel不能保證不被人為編輯,那么就很有可能,我們在進行合并單元格的時候,把有值和無值合并到一起,最后就出現前面提到的讀取合并單元格出現數據缺失的問題。 而我們期望,合并單元格部分他們的數據應該是一樣的。所以今天的解決方案是一種保險的做法,不管你的表格是否有合并單元格,是否人為修改,最終都能把合并單元格缺失的數據進行恢復。
到此這篇關于easyexcel讀取excel合并單元格數據的操作代碼的文章就介紹到這了,更多相關easyexcel合并單元格數據內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringMVC + servlet3.0 文件上傳的配置和實現代碼
本篇文章主要介紹了SpringMVC + servlet3.0 文件上傳的配置和實現代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04
Spring+SpringMVC配置事務管理無效原因及解決辦法詳解
這篇文章主要介紹了Spring+SpringMVC配置事務管理無效原因及解決辦法詳解,具有一定借鑒價值,需要的朋友可以參考下2017-12-12
Spring Boot中自定義注解結合AOP實現主備庫切換問題
這篇文章主要介紹了Spring Boot中自定義注解+AOP實現主備庫切換的相關知識,本篇文章的場景是做調度中心和監(jiān)控中心時的需求,后端使用TDDL實現分表分庫,需要的朋友可以參考下2019-08-08

