美文网首页
easyexcel导入简单封装

easyexcel导入简单封装

作者: 水煮鱼又失败了 | 来源:发表于2021-02-21 15:47 被阅读0次

    1 场景

    本文主要对EasyExcel的功能进行简单封装,实现我们在读取excel中的简单操作。
    实现以下功能,能满足大多数情况下的Excel文件读取(03版本、07版本+大数据量导入):

    (1)获取列索引对应表头(第一行为表头),获取表头主要用于判断
    (2)以字符串的形式获取单元格内容,形式为(列号,单元格内容

    2 版本

    EasyExcel:2.2.7

    3 maven依赖

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

    4 代码

    4.1 数据处理器接口

    读取每xxx条(默认1000条)数据,调用一次数据处理接口

    package com.sa.example.easyexcel.util;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * 数据处理器
     */
    public interface BaseProcessor {
        
        /**
         * 回调方法
         * @param list
         */
        void invoke(List<Map<Integer,String>> list);
    }
    

    4.2 工具类

    (1)工具类方法说明如下:

    • 读取excel表头
    // 读取前多少条的表头(第一行数据),封装到List<String>中返回
    public static List<String> getExcelHead(InputStream inputStream, Integer headSize);
    // 获取所有有内容的表头数据
    public static List<String> getExcelHead(InputStream inputStream);
    
    • 读取excel数据
    // 读取1000条数据后,调用一次数据处理器BaseProcessor
    public static long readData(InputStream inputStream, BaseProcessor baseProcessor);
    // 读取指定条数据batchSize,调用一次数据处理器BaseProcessor
    public static long readData(InputStream inputStream, BaseProcessor baseProcessor, final Integer batchSize);
    

    (2)完整工具类代码如下:

    package com.sa.example.easyexcel.util;
    
    import com.alibaba.excel.EasyExcel;
    import com.alibaba.excel.context.AnalysisContext;
    import com.alibaba.excel.event.AnalysisEventListener;
    import org.apache.commons.collections4.CollectionUtils;
    import org.apache.commons.collections4.MapUtils;
    
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.atomic.AtomicBoolean;
    import java.util.concurrent.atomic.AtomicLong;
    
    /**
     * Excel工具类
     */
    public class ExcelUtil {
        
        /**
         * 行号索引
         */
        public static final Integer ROW_NUMBER_INDEX = -1;
        
        private ExcelUtil() {
            
        }
        
        /**
         * 读取Excel表头
         * @param inputStream 输入流
         * @param headSize    excel表头个数(指定返回的个数)
         * @return
         */
        public static List<String> getExcelHead(InputStream inputStream, Integer headSize) {
            List<String> excelHeadList = getExcelHead(inputStream);
            if (headSize != null && headSize > 0 && CollectionUtils.isNotEmpty(excelHeadList) && excelHeadList.size() >= headSize) {
                return excelHeadList.subList(0, headSize);
            }
            
            return excelHeadList;
        }
        
        
        /**
         * 读取Excel表头
         * @param inputStream 输入流
         * @return excel表头
         */
        public static List<String> getExcelHead(InputStream inputStream) {
            // 表头名称列表
            final List<String> headList = new ArrayList<>();
            
            //继续执行标志
            final AtomicBoolean execFlag = new AtomicBoolean(true);
            
            EasyExcel.read(inputStream, new AnalysisEventListener<Map<Integer, String>>() {
                
                @Override
                public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
                    if (MapUtils.isNotEmpty(headMap)) {
                        for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
                            headList.add(entry.getValue());
                        }
                    }
                    // 终止读取
                    execFlag.set(false);
                }
                
                @Override
                public void invoke(Map<Integer, String> data, AnalysisContext context) {
                    // Do nothing
                }
                
                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    // Do nothing
                }
                
                @Override
                public boolean hasNext(AnalysisContext context) {
                    return execFlag.get();
                }
            }).sheet().doRead();
            return headList;
        }
        
        /**
         * 读取数据 (默认1000)
         * @param inputStream 文件流
         * @param baseProcessor 自定义处理器
         * @return 读取数据总数量
         */
        public static long readData(InputStream inputStream, BaseProcessor baseProcessor) {
            return readData(inputStream, baseProcessor, 1000);
        }
        
        
        /**
         * 读取数据
         * @param inputStream   文件流
         * @param baseProcessor 处理器
         * @param batchSize     单批次处理数量
         * @return 读取数据总数量
         */
        public static long readData(InputStream inputStream, BaseProcessor baseProcessor, final Integer batchSize) {
            
            // 数据行数
            final AtomicLong dataCount = new AtomicLong(0L);
            
            EasyExcel.read(inputStream, new AnalysisEventListener<Map<Integer, String>>() {
                
                /**
                 * 缓存集合
                 */
                private List<Map<Integer, String>> list = new ArrayList<>(batchSize);
                
                /**
                 * 当前行号
                 */
                private Integer lineNumber = 1;
                
                @Override
                public void invoke(Map<Integer, String> data, AnalysisContext context) {
                    lineNumber++;
                    // 记录总行数
                    dataCount.addAndGet(1);
                    if (list.size() >= batchSize) {
                        // 批量执行任务
                        if (baseProcessor != null) {
                            baseProcessor.invoke(list);
                        }
                        // 清除缓存
                        list.clear();
                    } else {
                        // 记录行号
                        data.put(ROW_NUMBER_INDEX, String.valueOf(lineNumber));
                        // 写入缓存表
                        list.add(data);
                    }
                }
                
                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    if (baseProcessor != null) {
                        baseProcessor.invoke(list);
                    }
                }
            }).sheet().doRead();
            return dataCount.get();
        }
        
    }
    

    5 使用

    使用到的excel文件《电话区域表.xlsx》如下:

    电话区域表.xlsx.png

    5.1 测试代码

    这里设定,每读取6条记录,执行一次数据处理。

    // 声明要读取的文件
    File file = new File("D:\\电话区域表.xlsx");
    
    // ==========【一、读取表头】==========
    final List<String> headList = new ArrayList<>();
    try (InputStream inputStream = new FileInputStream(file)) {
        headList.addAll(ExcelUtil.getExcelHead(inputStream));
        System.out.println("获取表头:" + headList + "\n");
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    // ==========【二、读取文件内容】==========
    try (InputStream inputStream = new FileInputStream(file)) {
        long readDataCount = ExcelUtil.readData(inputStream, list -> {
            System.out.println("----------开始调用数据处理----------");
            // 持久化存储
            List<Map<String, Object>> dbDataMapList = new ArrayList<>();
            int headSize = headList.size();
            for (Map<Integer, String> dataMap : list) {
                Map<String, Object> dbDataMap = new HashMap<>(headSize + 1);
                // 行号
                dbDataMap.put("行号", Integer.valueOf(dataMap.get(ExcelUtil.ROW_NUMBER_INDEX)));
                // 导入数据
                for (int i = 0; i < headSize; i++) {
                    dbDataMap.put(headList.get(i), dataMap.get(i));
                }
                System.out.println("获取数据:" + dbDataMap);
            }
        }, 6);
        System.out.println("\n----------读取数据总数量:" + readDataCount + "----------");
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    5.2 输出内容

    获取表头:[前缀号段, 手机所在省份, 手机所在城市, 服务商]
    
    ----------开始调用数据处理----------
    获取数据:{前缀号段=1300000, 手机所在城市=济南, 行号=2, 手机所在省份=山东, 服务商=中国联通}
    获取数据:{前缀号段=1300001, 手机所在城市=常州, 行号=3, 手机所在省份=江苏, 服务商=中国联通}
    获取数据:{前缀号段=1300002, 手机所在城市=巢湖, 行号=4, 手机所在省份=安徽, 服务商=中国联通}
    获取数据:{前缀号段=1300003, 手机所在城市=宜宾, 行号=5, 手机所在省份=四川, 服务商=中国联通}
    获取数据:{前缀号段=1300004, 手机所在城市=自贡, 行号=6, 手机所在省份=四川, 服务商=中国联通}
    获取数据:{前缀号段=1300005, 手机所在城市=西安, 行号=7, 手机所在省份=陕西, 服务商=中国联通}
    ----------开始调用数据处理----------
    获取数据:{前缀号段=1300007, 手机所在城市=西安, 行号=9, 手机所在省份=陕西, 服务商=中国联通}
    获取数据:{前缀号段=1300008, 手机所在城市=武汉, 行号=10, 手机所在省份=湖北, 服务商=中国联通}
    获取数据:{前缀号段=1300009, 手机所在城市=西安, 行号=11, 手机所在省份=陕西, 服务商=中国联通}
    
    ----------读取数据总数量:10----------
    

    相关文章

      网友评论

          本文标题:easyexcel导入简单封装

          本文链接:https://www.haomeiwen.com/subject/jdsqfltx.html