java EasyExcel实现动态列解析和存表

 更新时间:2023年06月15日 17:28:32   作者:我是一颗小虎牙_  
这篇文章主要为大家介绍了java EasyExcel实现动态列解析和存表示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

背景

一个表中的数据来源于多个其他系统的导出表,其中的特点就是大多数的字段都是一样的(可能导出的表头不一样),只有部分少数字段是每个系统自己独有的。围绕这个做一次功能性分析

分析:大多数字段是一样的,那么就是实际的表字段,唯一的区别就是各系统内的名字可能不一样,少数每个系统独有的字段,可以归为动态字段。

总结:

  • 公共字段(翻译表头:@ExcelProperty 可以指定多个表头( @ExcelProperty(value = {"发货数量", "采购数量(台)"}) ))
  • 动态字段(需要有每个系统内动态字段的字段名称和表头的对应关系,考虑使用字典,供业务员配置,后续如果新添加其他动态字段直接在字典中配置,无需另行开发)

注意:由于无法控制和预料固定字段在新接入的系统中的实际表头,所以如果新接入系统的公共表头与表字段不一致,需要在 @ExcelProperty(value = {}) 中添加新的表头

效果

字典配置:

数据表结果:

公共字段使用常规的数据库表字段存储,动态字段使用额外列存 JSON 串。

代码

引入pom坐标

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.1.0</version>
</dependency>

创建实体类

public class AgentDeliverOrderImportVo {
    @ExcelProperty(value = {"订单编号"}, order = 1)
    private String deliverNo;
    @ExcelProperty(value = {"发货数量", "采购数量(台)"}, order = 14)
    @ColumnName(name = {"发货数量", "采购数量(台)"})
    private Integer deliverCount;
    /**
     * 动态字段(业务线编号区分)
     */
    private String dynamicFields;
    private Date createTime;
    private String createBy;
}
  • 因为存在不确定的列,所以只能使用 EasyExcel 的不创建对象的写,那么
public String test(MultipartFile file) throws IOException {
    //假设从字典中获取字典值
    Map<String, String> dictMap = new HashMap<>();
    dictMap.put("项目", "xm");
    dictMap.put("嗨一付订单编号", "hyfddbh");
    try (InputStream inputStream = file.getInputStream()) {
        EasyExcel.read(inputStream, new ReadListener<Map<String, String>>(){
            private Map<Integer, String> fieldHead;
            //获取表头
            @Override
            public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
                Map<Integer, String> integerStringMap = ConverterUtils.convertToStringMap(headMap, context);
                log.info("解析到一条头数据:{}", JSON.toJSONString(integerStringMap));
                fieldHead = ExcelParsing.setFieldHead(integerStringMap, AgentDeliverOrderImportVo.class);
                log.info("转化后头数据:{}", JSONObject.toJSONString(fieldHead));
            }
            //获取数据
            @Override
            public void invoke(Map<String, String> map, AnalysisContext analysisContext) {
                log.info("解析到一条数据:{}", JSON.toJSONString(map));
                Map<String, String> valueMap = ExcelParsing.setFieldValue(fieldHead, dictMap, map);
                log.info("转化一条数据:{}", JSONObject.toJSONString(valueMap));
                log.info("转化一条动态数据:{}", JSONObject.toJSONString(ExcelParsing.getValueMap(valueMap, AgentDeliverOrderImportVo.class)));
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            }
        }).sheet().doRead();
    }
    return "完成";
}
/**
 * @author Surpass
 * @Description: excel处理类
 * @date 27/07/2022 15:04
 */
class ExcelParsing {
    /**
     * 将公共字段中的中文转换成数据库表字段,动态字段(其他字段保留)
     * @param headMap               {1:"姓名", 2:"年龄"}
     * @param obj                   AgentDeliverOrderImportVo(导入实体类)
     * @return java.util.Map<java.lang.String, java.lang.String>       {1:"name", 2:"年龄"}
     * @author Surpass
     * @date 01/08/2022 17:10
     */
    public static Map<Integer, String> setFieldHead(Map<Integer, String> headMap, Class<?> obj) {
        Field[] fields = obj.getDeclaredFields();
        for (Field field : fields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation == null) {
                continue;
            }
            //存在翻译字段的情况,一个字段对应好几个表头(尽量避免)
            List<String> valueList = Arrays.asList(annotation.value());
            for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
                if (valueList.contains(entry.getValue())) {
                    headMap.put(entry.getKey(), field.getName());
                }
            }
        }
        return headMap;
    }
    /**
     * 获取数据(平铺),指动态字段kv和公共字段kv在同一级
     * @param headMap               {1:"name", 2:"年龄"}
     * @param dictMap               {"年龄":"age"}
     * @param valueMap              {1:"广州****公司", 2:"23"}
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @author Surpass
     * @date 01/08/2022 17:10
     */
    public static Map<String, String> setFieldValue(Map<Integer, String> headMap,
                                                    Map<String, String> dictMap,
                                                    Map<String, String> valueMap) {
        Map<Integer, String> valueIntegerMap = valueMap.entrySet().stream().collect(
                Collectors.toMap(item -> Integer.valueOf(String.valueOf(item.getKey())),
                        item -> StrUtil.nullToEmpty(item.getValue()))
        );
        Map<String, String> valueResultMap = new HashMap<>(valueMap.size());
        Iterator<Map.Entry<Integer, String>> iterator = valueIntegerMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> entry = iterator.next();
            //动态字段
            if (dictMap != null && dictMap.containsKey(headMap.get(entry.getKey()))) {
                valueResultMap.put(dictMap.get(headMap.get(entry.getKey())), entry.getValue());
                continue;
            }
            //公共字段
            valueResultMap.put(headMap.get(entry.getKey()), entry.getValue());
            iterator.remove();
        }
        return valueResultMap;
    }
    /**
     * 获取数据(表结构),指动态字段kv已经加入到数据库表字段 dynamicFields 中
     * @param obj                   AgentDeliverOrderImportVo(导入实体类)
     * @param valueMap              {"name":"广州****公司", "age":"23"}
     * @return java.util.Map<java.lang.String, java.lang.String>  
     * 返回结果: {"name":"广州****公司","dynamicFields":{"age":"23"}}
     * @author Surpass
     * @date 01/08/2022 17:10
     */
    public static Map<String, Object> getValueMap(Map<String, String> valueMap,
                                                  Class<?> obj) {
        Map<String, Object> resultMap = new HashMap<>(valueMap);
        List<String> commonFieldList = new ArrayList<>();
        Field[] fields = obj.getDeclaredFields();
        for (Field field : fields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation == null) {
                continue;
            }
            commonFieldList.add(field.getName());
        }
        //过滤掉实体中的公共字段
        Map<String, String> dynamicMap = valueMap.entrySet().stream()
                .filter(item -> !commonFieldList.contains(item.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        resultMap.put("dynamicFields", dynamicMap);;
        return resultMap;
    }
}

经过解析以后这个文档的数据已经和数据库表一致了,那么我们后续的操作就是常规的校验和插入逻辑了。

目前有一个缺点就是这样存的动态字段不好做条件查询,影响不是很大。

总结

本文介绍了使用 EasyExcel 组件来进行导入,实现公共列和动态列组合类型的导入,以及如何存储的功能,主要利用反射和字典分别来维护公共列和动态列的表头和字段的对应关系,利用此关系对数据进行解析。

以上就是java EasyExcel实现动态列解析和存表的详细内容,更多关于java EasyExcel动态列存表的资料请关注脚本之家其它相关文章!

相关文章

  • JAVA内部类示例详解及练习

    JAVA内部类示例详解及练习

    这篇文章主要为大家详细介绍了Java的内部类,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • intelij idea 2023创建java web项目的完整步骤

    intelij idea 2023创建java web项目的完整步骤

    这篇文章主要给大家介绍了关于intelij idea 2023创建java web项目的完整步骤,该教学主要针对各位刚刚接触javaweb开发的小伙伴,各位学习java的朋友也难免会经历这个阶段,需要的朋友可以参考下
    2023-10-10
  • Java实现Excel转PDF的两种方法详解

    Java实现Excel转PDF的两种方法详解

    使用具将Excel转为PDF的方法有很多,在这里我给大家介绍两种常用的方法:使用spire转化PDF、使用jacob实现Excel转PDF,分别应对两种不一样的使用场景,需要的可以参考一下
    2022-01-01
  • @Transactional跟@DS动态数据源注解冲突的解决

    @Transactional跟@DS动态数据源注解冲突的解决

    这篇文章主要介绍了@Transactional跟@DS动态数据源注解冲突的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Mybatis控制台打印Sql语句的实现代码

    Mybatis控制台打印Sql语句的实现代码

    MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架,下面给大家介绍Mybatis控制台打印Sql语句的实现代码,非常不错,感兴趣的朋友一起看下吧
    2016-07-07
  • Java NIO原理图文分析及代码实现

    Java NIO原理图文分析及代码实现

    本文主要介绍Java NIO原理的知识,这里整理了详细资料及简单示例代码和原理图,有需要的小伙伴可以参考下
    2016-09-09
  • 初次使用IDEA创建maven项目的教程

    初次使用IDEA创建maven项目的教程

    这篇文章主要介绍了初次使用IDEA创建maven项目的教程讲解,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-01-01
  • 浅析java异常栈

    浅析java异常栈

    给大家通过一个简单的代码实例给大家分型了java异常栈问题,需要的朋友参考一下吧。
    2017-12-12
  • 重新理解Java泛型

    重新理解Java泛型

    这篇文章主要介绍了重新理解Java泛型,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • 解决maven中只有Lifecycle而Dependencies和Plugins消失的问题

    解决maven中只有Lifecycle而Dependencies和Plugins消失的问题

    这篇文章主要介绍了maven中只有Lifecycle而Dependencies和Plugins消失的问题及解决方法,本文通过图文的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-07-07

最新评论