easyExcel中合并单元格文件读取实现方案

1.需求场景描述
2.问题分析与实现方案

1.需求场景描述

    现在有个业务需要按照指定模板上传选择题,并进行入表处理,使用easyExcel进行文件上传并读取数据,其中涉及合并单元数据读取问题,这里简单记录一下实现过程,希望对有同样需求的同学有所帮助.下面贴一下文件上传的模板:
在这里插入图片描述
其中每个选择题的题干部分是合并单元格,每个选择题的四个固定选项分别占一行。入表之前期望读取的数据格式为:
在这里插入图片描述
2.问题分析与实现方案

    对于此种场景,根据easy excel读取原理,每行读取完成都支持进行监听回调(可自定义监听器执行invoke中获取所有行数读取信息),所有行数读取完成之后将组装数据进行输出(所有行数读取完成会执行自定义监听器中doAfterAllAnalysed)。按照一般读取操作发现都是按照合并前的行数进行读取。以展示模板信息为例说讲,表格中8行数据,就是进行了8次读取,对于合并单元格所在的列,只有第一行进行了实体类属性数据映射,对于合并过的单元格对应的实体类属性值均为null。以下为代码调试展示说明:
每道题第一行读取的实体类属性值:
每道题第一行之外读取的实体类属性值:
所以可以将每行读取完成之后的数据进行组装即可,这里添加了一下目标数据格式类: ExamInfo.java
下面贴一下案例代码:
easy excel文件读取类(与模板文件对应):

public class ExamMsg {

    @ExcelProperty("题目描述")
    private String answer;

    @ExcelProperty("考试答案")
    private String stem;

    @ExcelProperty("考试答案分析")
    private String analyse;

    @ExcelProperty("题目单项分数")
    private Integer singleScore;


    @ExcelProperty("选项")
    private String choiceType;

    @ExcelProperty("选项内容")
    private String optionContent;
	
	// 省略get/set
}

目标数据组装类(入表之前的最终数据格式):

public class ExamInfo {

    private String answer;

    private String stem;

    private String analyse;

    private Integer singleScore;

    private List<EaxmChoiceInfo> eaxmChoiceInfoList=new ArrayList<>();
// 省略get/set
}

每个选择题的四个选择项实体类:

public class EaxmChoiceInfo {

    private String choiceType;

    private String optionContent;
    // 省略get/set
}

自定义监听器

public class ExamListener implements ReadListener<ExamMsg> {

  // 自定义消费者函数接口用于自定义监听器中数据组装
    private final Consumer<List<ExamInfo>> consumer;

    public ExamListener(Consumer<List<ExamInfo>> consumer) {
        this.consumer = consumer;
    }

    // easy excel读取参数
    private List<ExamMsg> examMsgList=new ArrayList<>();
    // 封装读取对象
    private List<ExamInfo> examInfoList=new ArrayList<>();
    // 每行读取完成之后会执行
    @Override
    public void invoke(ExamMsg data, AnalysisContext context) throws IllegalAccessException {

        // 按照格式组装数据
        if(data.getStem() != null){
            ExamInfo examInfo = new ExamInfo();
            BeanUtils.copyProperties(data,examInfo);
            examInfo.getEaxmChoiceInfoList().add(new EaxmChoiceInfo(data.getChoiceType(),data.getOptionContent()));
            examInfoList.add(examInfo);
        }else {
            // 倒序添加选择题信息,只对最后一个进行添加选项数据信息
                examInfoList.get(examInfoList.size() - 1).getEaxmChoiceInfoList().add(new EaxmChoiceInfo(data.getChoiceType(),data.getOptionContent()));
        }
    }
	// 每行读取完成之后执行
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
         if (CollectionUtils.isNotEmpty(examInfoList)) {
            consumer.accept(examInfoList);
        }
    }
}

文件读取测试类:

public class PersonalExcel {

    public static void main(String[] args) {
List<ExamInfo> examInfoList=new ArrayList<>();
        String fileName = "E:\\项目汇总\\选择题录入模板" + ".xlsx";


      
       EasyExcel.read(fileName, ExamMsg.class, new ExamListener(examInfos -> {
            for (ExamInfo examInfo : examInfos) {
                examInfoList.add(examInfo);
            }
        })).sheet().doRead();
        System.out.println(examInfoList);
    }
    }

    控制台打印读取数据:

[ExamInfo{answer='新冠肺炎起源于哪一年?', stem='A', analyse='经验得知', singleScore=2, 
		eaxmChoiceInfoList=[EaxmChoiceInfo{choiceType='A', optionContent='2019'}, 
							EaxmChoiceInfo{choiceType='B', optionContent='2022'},
							EaxmChoiceInfo{choiceType='C', optionContent='2021'},
							EaxmChoiceInfo{choiceType='D', optionContent='2003'}]},
	ExamInfo{answer='刘备的最好的朋友是谁?', stem='B', analyse='猜的', singleScore=2, 
		eaxmChoiceInfoList=[EaxmChoiceInfo{choiceType='A', optionContent='关羽'},
							EaxmChoiceInfo{choiceType='B', optionContent='诸葛亮'},
							EaxmChoiceInfo{choiceType='C', optionContent='张飞'}, EaxmChoiceInfo{choiceType='D', optionContent='曹操'}]}]

    以上为处理合并单元格文件读取的实现方案,如果对你有帮助欢迎点赞收藏!
更多easy excel实战文章:
    Easy excel实战:读取文件自定义转化器不生效问题处理方案
     EasyExcel实战:实现导入文件参数校验并记录异常信息

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卖柴火的小伙子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值