栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

EasyExcel支持导入动态列

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

EasyExcel支持导入动态列

文章目录
  • 前言
  • 一、代码
  • 二、使用
  • 二、结束


前言

我们在使用EasyExcel做导入功能时,通过在实体或者VO加@ExcelProperty(“测试”)注解来实现列的一一对应,read()之后获取一个List的结果集,得到java的数据类型然后在进行业务操作
但EasyExcel这种通过注解的方式实现导入就必须使用事先定义好数据类型来接收,它不支持对象中的子对象,也不能导入excel带有动态列的数据(即相同列名下的多个数据列)
换做java的数据结构即如下结构:

这里使用原生的EasyExcel并不能接收到多个列名为 测试1 的数据
这里提供一种解决方式,它能够实现动态列的解析,实例化对象中的子对象这种数据结构(仅支持二级的嵌套,即一对多的这种关系)


一、代码
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ExcelDynamic {
}

public class DynamicReadListener extends AnalysisEventListener>> {

    
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    
    private final List> headList = new ArrayList<>();

    
    private final List> dataList = new ArrayList<>();

    
    private final List> dynamicIndex = new ArrayList<>();

    
    private final List>> dynamicColumns = new ArrayList<>();

    
    public static DynamicReadListener init(){
        return new DynamicReadListener();
    }

    
    @Override
    public void invokeHeadMap(Map headMap, AnalysisContext context) {
        log.info("解析到表头:{}", JsonUtil.toJson(headMap));
        //保存表头
        headList.add(headMap);
        //保存动态列索引
        //CollectUtil.repeatNode(headMap) 获取map中重复value的keys
        dynamicIndex.add(CollectUtil.repeatNode(headMap));
    }


    @Override
    public void invoke(Map> data, AnalysisContext context) {
        
        //dataList.add(data);
        ReadSheetHolder holder = context.readSheetHolder();
        try {
            handleDynamicColumns(data, holder.getHeadRowNumber() - 1, holder.getRowIndex() - 1, headList.size());
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {}

    
    private void handleDynamicColumns(Map> data, Integer headRowIndex, Integer dataRowIndex, Integer columnSize) throws NoSuchFieldException, IllegalAccessException {
        if (!dynamicIndex.isEmpty()){
            Map> columns = new HashMap<>(columnSize);
            Map targetHead = headList.get(headRowIndex);
            for (Integer targetIndex : dynamicIndex.get(headRowIndex)) {
                String head = targetHead.get(targetIndex);
                String value = data.get(targetIndex).getStringValue();
                if (Objects.isNull(columns.get(head))){
                    //不要使用Arrays.asList 因为返回的list 没有重写add方法
                    columns.put(head, ListUtil.asList(value));
                }else {
                    columns.get(head).add(value);
                }
            }
            dynamicColumns.add(columns);
        }
    }

    public List> getHeadList() {
        return headList;
    }

    public List> getDataList() {
        return dataList;
    }

    public List>> getDynamicColumns() {
        return dynamicColumns;
    }
}
public class Excels extends EasyExcel{

    private Excels() {}

    
    public static  List imports(InputStream fileStream, Class clazz){
        return read(fileStream).head(clazz).sheet().doReadSync();
    }

    
    public static  List importsDynamic(InputStream fileStream, Class clazz) throws IllegalAccessException, InstantiationException {
        //初始化 处理动态列 readListener
        DynamicReadListener dynamicReadListener = DynamicReadListener.init();
        //初始化 同步读取数据 readListener
        SyncReadListener syncReadListener = new SyncReadListener();
        
        ExcelReaderSheetBuilder sheet = read(fileStream).useDefaultListener(false).head(clazz).sheet();
        sheet.registerReadListener(dynamicReadListener);
        //注册 map转 model readListener
        sheet.registerReadListener(new ModelBuildEventListener());
        sheet.registerReadListener(syncReadListener);
        sheet.doRead();
        return build((List) syncReadListener.getList(), dynamicReadListener);
    }

    
    private static  List build(List targets, DynamicReadListener listener) throws IllegalAccessException, InstantiationException {
        if (CollectionUtils.isNotEmpty(targets)){
            for (int i = 0; i < targets.size(); i++) {
                T target = targets.get(i);
                // 初始化带有 @ExcelDynamic 标志的属性
                for (Field targetField : target.getClass().getDeclaredFields()) {
                    if (Objects.nonNull(targetField.getAnnotation(ExcelDynamic.class))){
                        targetField.setAccessible(true);
                        targetField.set(target, build(listener.getDynamicColumns().get(i), targetField.getType()));
                    }
                }
            }
        }
        return targets;
    }

    
    private static  T build(Map> dynamicRow, Class clazz) throws InstantiationException, IllegalAccessException {
        if (Objects.isNull(clazz)){
            throw new NullPointerException("class not support null value");
        }
        //处理类型属性list
        Field[] fields = clazz.getDeclaredFields();
        //待处理命中动态列数据
        Map> hitColumn = new HashMap<>(fields.length);
        //开始筛选命中动态列
        dynamicRow.forEach((head, columns)->{
            //遍历  属性
            for (Field field : fields) {
                //获取属性注解
                ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                if (Objects.nonNull(annotation)){
                    //根据注解值匹配
                    Object[] annotationKeys = annotation.value();
                    for (Object annotationKey : annotationKeys) {
                        if (!Objects.equals("", annotationKey) && Objects.equals(head, annotationKey)){
                            if (CollectionUtils.isNotEmpty(columns)){
                                hitColumn.put(field, columns);
                                break;
                            }
                        }
                    }
                }
            }
        });
        return handle(hitColumn, clazz);
    }

    
    private static  T handle(Map> hitColumn, Class clazz) throws InstantiationException, IllegalAccessException {
        //处理返回结果
        if(CollectionUtils.isNotEmpty(hitColumn.keySet())){
            T target = clazz.newInstance();
                hitColumn.forEach((field, columns) -> {
                    try {
                        List targetFieldList = new ArrayList<>();
                        for (Object column : columns) {
                            try {
                                Object targetValue = Objects.requireNonNull(getGenericClass(field)).getConstructor(String.class).newInstance((String)column);
                                targetFieldList.add(targetValue);
                            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                                e.printStackTrace();
                            }
                        }
                        field.setAccessible(true);
                        field.set(target, targetFieldList);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                });
            return target;
        }
        return null;
    }

    
    private static Class getGenericClass(Field field){
        Type genericType = field.getGenericType();
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            // 获取成员变量的泛型类型信息
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                return (Class) actualTypeArgument;
            }
        }
        return null;
    }
}

 
二、使用 

文件数据

测试

	
    @Test
    public void test1() throws FileNotFoundException, IllegalAccessException, InstantiationException {
        List as = Excels.importsDynamic(new FileInputStream(new File("C:\Users\caobinghui\Desktop\test.xlsx")), A.class);
        as.forEach(System.out::println);
    }

结果

二、结束

代码拙劣,大家可以自己去试着优化
觉得有帮助的可以点个赞,谢谢!!


我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号