easyexcel lee datos de celdas fusionadas de Excel

    No hay ningún problema en easyexcel para leer listas de Excel ordinarias. Sin embargo, si hay celdas fusionadas, cuando se leen, se pueden obtener los datos, pero están incompletos. Datos de la celda como se muestra a continuación:

    Usamos lectura asincrónica simple y finalmente vemos el contenido de los datos:

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

    Ejecute el programa e imprima la información del registro de la siguiente manera:

   Es cierto que se han obtenido 6 datos, pero un dato en cada registro de celda fusionado está vacío.

    La solución es leer los datos adicionales de las celdas fusionadas en el detector de datos de lectura asincrónica y complementar esta parte de los datos.

    Qué es necesario modificar:

    1. La entidad necesita agregar el valor del índice de anotación:

@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. Personalice el oyente para leer datos de celdas fusionadas:

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. Lea los datos a través del oyente, obtenga los datos y combine los datos de la celda a través del oyente, y luego configure los datos de la celda.


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

    Hay un pequeño detalle a tener en cuenta: cuando leemos el oyente, necesitamos leer adicionalmente las celdas fusionadas.

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

    Otro pequeño detalle es que nuestras tablas generalmente tienen un encabezado, el contenido del encabezado puede ser de 2 filas o 1 fila, al fusionar celdas es necesario considerar este número de filas. Definimos una constante HEAD_ROW_NUM para registrar el número de filas y la pasamos cuando finalmente calculamos el valor de la celda. 

    Al procesar datos de Excel, descubrí que si nuestro programa mismo realiza la combinación de celdas, no habrá ningún problema cuando se lea. Dondequiera que sea nulo arriba, en realidad tiene un valor:

    Pero en la práctica, nuestro Excel no puede garantizar que no se editará manualmente, por lo que es muy probable que cuando fusionemos celdas, fusionemos los valores y los no valores, y finalmente la fusión de lectura mencionada anteriormente. ocurrirá Hay un problema con datos faltantes en la celda. Y esperamos que sus datos en las celdas fusionadas sean los mismos. Por lo tanto, la solución de hoy es un enfoque seguro: independientemente de si su tabla tiene celdas fusionadas o si se ha modificado manualmente, eventualmente podrá recuperar los datos faltantes en las celdas fusionadas.

Supongo que te gusta

Origin blog.csdn.net/feinifi/article/details/130437926
Recomendado
Clasificación