• 使用EasyExcel导入导出Excel look


    使用EasyExcel导入导出Excel

    1、官方网站

    https://github.com/alibaba/easyexcel

    快速开始:https://www.yuque.com/easyexcel/doc/easyexcel

    使用场景

    在日常开发中 我们难免需要导入数据 可以用EasyExcel来解决

    2、EasyExcel特点

    • Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
    • EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
    • EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。

    3、动起手来

    创建一个普通maven项目 加入依赖

    <dependencies>
    
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.7</version>
        </dependency>
    
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.5</version>
        </dependency>
    
        <dependency>
            <groupId>org.apache.xmlbeans</groupId>
            <artifactId>xmlbeans</artifactId>
            <version>3.1.0</version>
        </dependency>
    
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    
    </dependencies>
    

    3.1excel示例

    image-20220510234118851

    3.2 实体类

    我们需要创建好与excel列名相对应的实体类

    @ExcelProperty 表示excel列名

        package com.atguigu.easyexcel.dto;
    
        @Data
        public class ExcelStudentDTO {
    
            @ExcelProperty("姓名")
            private String name;
    
            @ExcelProperty("生日")
            private Date birthday;
    
            @ExcelProperty("薪资")
            private Double salary;
        }
    

    3.3 测试起来吧

    1 简单的写

    public class ExcelWriteTest {
        @Test
        public void simpleWriteXlsx() {
            String fileName = "d:/excel/simpleWrite.xlsx"; //需要提前新建目录
            // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
            EasyExcel.write(fileName, ExcelStudentDTO.class).sheet("模板").doWrite(data());
        }
        
        //辅助方法
        private List<ExcelStudentDTO> data(){
            List<ExcelStudentDTO> list = new ArrayList<>();
    
            //算上标题,做多可写65536行
            //超出:java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)
            for (int i = 0; i < 65535; i++) {
                ExcelStudentDTO data = new ExcelStudentDTO();
                data.setName("Helen" + i);
                data.setBirthday(new Date());
                data.setSalary(123456.1234);
                list.add(data);
            }
    
            return list;
        }
    }
    

    结果就是上面那张图片哈 不粘了

    2 不同版本的写

    @Test
    public void simpleWriteXls() {
    
        String fileName = "d:/excel/simpleWrite.xls";
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, ExcelStudentDTO.class).excelType(ExcelTypeEnum.XLS).sheet("模板").doWrite(data());
    }
    

    3 读的操作

    参考文档https://www.yuque.com/easyexcel/doc/read

    简单描述一下 读的操作 需要实现一个监听器 实现监听器的方法

    @Slf4j
    public class ExcelStudentDTOListener extends AnalysisEventListener<ExcelStudentDTO> {
        
        /**
         * 这个每一条数据解析都会来调用
         */
        @Override
        public void invoke(ExcelStudentDTO data, AnalysisContext context) {
            log.info("解析到一条数据:{}", data);
    
        }
    
        /**
         * 所有数据解析完成了 都会来调用
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            log.info("所有数据解析完成!");
        }
    }
    

    测试方法

    public class ExcelReadTest {
    
        /**
         * 最简单的读
         */
        @Test
        public void simpleReadXlsx() {
    
            String fileName = "d:/excel/simpleWrite.xlsx";
            // 这里默认读取第一个sheet
            EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).sheet().doRead();
        }
    
        @Test
        public void simpleReadXls() {
    
            String fileName = "d:/excel/simpleWrite.xls";
            EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).excelType(ExcelTypeEnum.XLS).sheet().doRead();
        }
    }
    

    实战

    在真实的项目中 我们读取到 数据之后 肯定要持久化到数据库中 这个操作就由我们的监听器来完成

    1、Mapper层批量插入

    接口:DictMapper

    void insertBatch(List<ExcelDictDTO> list);
    

    xml:DictMapper.xml

    <insert id="insertBatch">
        insert into dict (
        id ,
        parent_id ,
        name ,
        value ,
        dict_code
        ) values
        <foreach collection="list" item="item" index="index" separator=",">
            (
            #{item.id} ,
            #{item.parentId} ,
            #{item.name} ,
            #{item.value} ,
            #{item.dictCode}
            )
        </foreach>
    </insert>
    

    2监听器的实现

    
    import com.alibaba.excel.context.AnalysisContext;
    import com.alibaba.excel.event.AnalysisEventListener;
    import com.atguigu.srb.mapper.DictMapper;
    import com.atguigu.srb.pojo.dto.ExcelDictDTO;
    import lombok.NoArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 监听
     * 再读取数据的同时 对数据进行插入操作
     * @author : look-word
     * @date : 2022-05-10 21:35
     **/
    @Slf4j
    //@AllArgsConstructor //全参
    @NoArgsConstructor //无参
    public class ExcelDictDTOListener extends AnalysisEventListener<ExcelDictDTO> {
    
      /**
         * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
         */
        private static final int BATCH_COUNT = 100;
        /**
         * 缓存的数据
         */
        private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        /**
         * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
         */
        private DemoDAO demoDAO;
    
        public DemoDataListener() {
            // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
            demoDAO = new DemoDAO();
        }
    
        /**
         * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
         *
         * @param demoDAO
         */
        public DemoDataListener(DemoDAO demoDAO) {
            this.demoDAO = demoDAO;
        }
    
        /**
         * 这个每一条数据解析都会来调用
         *
         * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
         * @param context
         */
        @Override
        public void invoke(DemoData data, AnalysisContext context) {
            log.info("解析到一条数据:{}", JSON.toJSONString(data));
            cachedDataList.add(data);
            // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
            if (cachedDataList.size() >= BATCH_COUNT) {
                saveData();
                // 存储完成清理 list
                cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }
    
        /**
         * 所有数据解析完成了 都会来调用
         *
         * @param context
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 这里也要保存数据,确保最后遗留的数据也存储到数据库
            saveData();
            log.info("所有数据解析完成!");
        }
    
        /**
         * 加上存储数据库
         */
        private void saveData() {
            log.info("{}条数据,开始存储数据库!", cachedDataList.size());
            demoDAO.save(cachedDataList);
            log.info("存储数据库成功!");
        }
    }
    
    
  • 相关阅读:
    UVa 12716 GCD XOR (简单证明)
    2.12 运行计划并取得数据行
    nyoj 628 小媛在努力 【搜索】
    ArcGIS Server 10.2 公布Oracle11g数据源的 Feature Service
    项目复习期总结3:CSS引入方式,凝视,命名规范,背景,行高,文本属性
    Android使用有道翻译API实如今线翻译功能
    _00017 Kafka的体系结构介绍以及Kafka入门案例(0基础案例+Java API的使用)
    夜&#183; 启程
    你不知道的JavaScript(六)Box&Unbox
    pugixml读取unicode编码的xml文件的做法
  • 原文地址:https://www.cnblogs.com/look-word/p/16256175.html
Copyright © 2020-2023  润新知