软件编程
位置:首页>> 软件编程>> java编程>> easyexcel读取excel合并单元格数据的操作代码

easyexcel读取excel合并单元格数据的操作代码

作者:luffy5459  发布时间:2022-08-26 16:26:21 

标签:easyexcel,合并,单元格数据

    普通的excel列表,easyexcel读取是没有什么问题的。但是,如果有合并单元格,那么它读取的时候,能获取数据,但是数据是不完整的。如下所示的单元格数据:

easyexcel读取excel合并单元格数据的操作代码

    我们通过简单的异步读取,最后查看数据内容:

  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());
   }
}

    运行程序,打印日志信息如下:

easyexcel读取excel合并单元格数据的操作代码

   获取了6个数据没错,但是每一个合并单元格记录里面都有一个数据获取是空的。

    解决办法就是需要在异步读取数据 * 里面读取合并单元格的额外数据,并把这部分数据给补充上。

    需要修改的地方:

    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、自定义 * ,读取合并单元格数据:

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、通过 * 读取数据,通过 * 获取数据和合并单元格数据,然后设置单元格数据。


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;
   }
}

    有个小细节需要注意,我们在通过 * 读取的时候,还需要额外读取合并单元格部分。

EasyExcel.read(FILEPATH, ExcelData.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();

    还有个小细节,就是我们的表格一般都是有头的,头的内容可能是2行,可能是1行,在进行合并单元格处理的时候,需要考虑这个行数。我们定义了一个常量HEAD_ROW_NUM来记录这个行数,最后进行单元格值计算的时候传入。 

    我在处理excel数据中发现,如果这个单元格合并,是由我们的程序自己做的,那么它读取的时候,是没有问题的。在上面为null的地方,它其实都有值:

easyexcel读取excel合并单元格数据的操作代码

    但是在实际中,我们的excel不能保证不被人为编辑,那么就很有可能,我们在进行合并单元格的时候,把有值和无值合并到一起,最后就出现前面提到的读取合并单元格出现数据缺失的问题。 而我们期望,合并单元格部分他们的数据应该是一样的。所以今天的解决方案是一种保险的做法,不管你的表格是否有合并单元格,是否人为修改,最终都能把合并单元格缺失的数据进行恢复。

来源:https://blog.csdn.net/feinifi/article/details/130437926

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com