EasyExcel批量读取Excel文件数据导入到MySQL表中

1、EasyExcel简介

官网:EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 官网

2、代码实战

首先引入jar包

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

2.1 读取Excel

2.1.1  使用PageReadListener

这种方式代码简洁,通俗易懂,直接看示例:

 public void readExcelFile2(MultipartFile file) {
    AtomicInteger count = new AtomicInteger(0);
    try {
          int batch = 10;
          EasyExcel.read(file.getInputStream(), SharePathApproveModule.class, new PageReadListener<SharePathApproveModule>(list -> {
             System.out.println("已完成" + list.size() + "条数据读取...");
             for (SharePathApproveModule module : list) {
                  System.out.println("读取到" + count.incrementAndGet() + "条数据=>" + JSONObject.toJSONString(module));

              }
              //批量写入
              //sharePathApproveMapper.insertBatch(list);
          }, batch)).sheet(0).doRead();
          //sheetNo参数不传默认0,读取第一个sheet;填0也是读取第1个sheet;填1即读取第2个sheet
      } catch (Exception e) {
          log.error("读取Excel数据异常,", e);
      }
  }

这种方式是直接使用了PageReadListener监听器,有兴趣的同学可以自行解读PageReadListener源码,这里我只把源码粘贴出来,本文主要讲实战,就不过多说PageReadListener。

import java.util.List;
import java.util.function.Consumer;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.util.ListUtils;

import org.apache.commons.collections4.CollectionUtils;

/**
 * page read listener
 *
 * @author Jiaju Zhuang
 */
public class PageReadListener<T> implements ReadListener<T> {
    /**
     * Default single handle the amount of data
     */
    public static int BATCH_COUNT = 100;
    /**
     * Temporary storage of data
     */
    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * consumer
     */
    private final Consumer<List<T>> consumer;

    /**
     * Single handle the amount of data
     */
    private final int batchCount;

    public PageReadListener(Consumer<List<T>> consumer) {
        this(consumer, BATCH_COUNT);
    }

    public PageReadListener(Consumer<List<T>> consumer, int batchCount) {
        this.consumer = consumer;
        this.batchCount = batchCount;
    }

    @Override
    public void invoke(T data, AnalysisContext context) {
        cachedDataList.add(data);
        if (cachedDataList.size() >= batchCount) {
            consumer.accept(cachedDataList);
            cachedDataList = ListUtils.newArrayListWithExpectedSize(batchCount);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (CollectionUtils.isNotEmpty(cachedDataList)) {
            consumer.accept(cachedDataList);
        }
    }

}

 简单的说一下PageReadListener监听器的两个方法:invoke和doAfterAllAnalysed;他们都是实现ReadListener接口里面定义的方法。

invoke:表示每解析完一条数据就会调用该初始方法,因此很多条件筛选或业务我们可以放在里面实现。

doAfterAllAnalysed:表示每解析完一个sheet页后调用该方法。

从源码中知道,invoke()中当数组的长度大于等于设置的长度时,则执Consumer,执行完成后在进行初始化集合;

doAfterAllAnalysed()中在获取完数据后,判断当前集合时候还有数据,有的话则执行Consumer。

2.1.2  自定义监听器

我们可以通过继承AnalysisEventListener类来自定义监听器,重新里面的invoke和doAfterAllAnalysed方法。

首先,新建一个Module

/**
 * @description
 * @date 2024-07-10 18:02
 **/
@Data
public class ShareModule {

    @ExcelProperty(value = "share路径", index = 0)
    @ColumnWidth(value = 10)
    private String sharePath;

    @ExcelProperty(value = "权限", index = 1)
    @ColumnWidth(value = 10)
    private String access;

    @ExcelProperty(value = "组名", index = 2)
    @ColumnWidth(value = 10)
    private String groupCn;

    @ExcelProperty(value = "历史申请人", index = 3)
    @ColumnWidth(value = 20)
    private String applicants;
}

接着,定义Mapper和Mapper.xml,这里我们只写一个批量插入的方法,使用

insert into table_name(column1,column2,column3) values(x,x,x),(x,x,x),.....

这种方式减少了数据库的连接,提高插入效率,而mybatis这样执行批处理需要在数据库url配置上添加rewriteBatchedStatements=true,进行批处理开启。

public interface ShareMapper {

    int insertBatch(@Param("shareModules")List<ShareModule> shareModules);

    int clearTableData();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.demo.mapper.ShareMapper">

    <insert id="insertBatch">
        INSERT INTO share_path_approve (share_path, access, group_cn, applicants) VALUES
        <foreach collection="shareModules" index="index" item="po" separator=",">
            (#{po.sharePath}, #{po.access}, #{po.groupCn}, #{po.applicants})
        </foreach>
    </insert>

    <update id="clearTableData">
        truncate table share_path_approve
    </update>

</mapper>

然后,就是自定义监听器,配将这个监听器交给Spring容器

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.wangpeng.mapper.SharePathApproveMapper;
import com.example.wangpeng.po.module.SharePathApproveModule;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * @description share auto
 * @date 2024-07-10 10:30
 */
@Slf4j
public class ShareListener extends AnalysisEventListener<ShareModule> {

    private List<ShareModule> cacheData = new ArrayList<>();
    private static final int BATCH_COUNT = 8;

    private final ShareMapper shareMapper;

    public SharePathApproveListener(ShareMapper shareMapper) {
        this.shareMapper= shareMapper;
    }


    @Override
    public void invoke(ShareModule shareModule, AnalysisContext analysisContext) {
        cacheData.add(shareModule);
        if (cacheData.size() >= BATCH_COUNT) {
            log.info("保存数据--share auto-----{}条", cacheData.size());
            saveData();
            // 可以清理缓存数据
            cacheData = new ArrayList<>();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 处理最后未达到8条数据的插入
        if (!cacheData.isEmpty()) {
            log.info("保存数据--share auto-----{}条", cacheData.size());
            saveData();
        }
    }

    private void saveData() {
        // 这里可以使用MyBatis的批量插入方法
        shareMapper.insertBatch(cacheData);
    }
}
import com.example.wangpeng.excel.SharePathApproveListener;
import com.example.wangpeng.mapper.SharePathApproveMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @description
 * @date 2024-07-10 18:17
 */
@Configuration
public class EasyExcelConfig {

    @Bean
    public ShareListener shareListener(ShareMapper shareMapper) {
        return new shareListener(shareMapper);
    }
}

最后一步,就是编写Service和实现类、控制层接口代码

public interface ExcelService {

    ResponseResult<?> importExcel(MultipartFile file, Integer type);

}
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.excel.ShareListener;
import com.example.demo.mapper.ShareMapper;
import com.example.demo.po.module.ShareModule;
import com.example.demo.response.ResponseResult;
import com.example.demo.service.ExcelService;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;


/**
 * @description
 * @date 2024-06-03 15:57
 */
@Log4j
@Service
public class ExcelServiceImpl implements ExcelService {

    @Autowired
    private SharePathApproveMapper sharePathApproveMapper;


    @Override
    public ResponseResult<?> importExcel(MultipartFile file, Integer type) {

        try (InputStream inputStream = file.getInputStream()) {
            if (0 == type) {
                //全量覆盖
                sharePathApproveMapper.clearTableData();
            }  //增量插入

            EasyExcel.read(inputStream, ShareModule.class, new ShareListener(shareMapper))
                    .sheet()
                    .doRead();

            return ResponseResult.success();
        } catch (Exception e) {
            log.info("ShareExcel并解析 异常!", e);
            return ResponseResult.fail(e.getMessage());
        }
    }
}

@RestController
@RequestMapping(value = "/excel")
public class ExcelController {

    @Autowired
    private ExcelService excelService;

    @PostMapping(value = "/import")
    public ResponseResult<String> excelFile2(@RequestBody MultipartFile file, Integer type) {
        excelService.importExcel(file, type);
        return ResponseResult.success();
    }
}

运行如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/797966.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于FPGA的千兆以太网设计(1)----大白话解释什么是以太网

1、什么是以太网? 还记得初学以太网的时候,我就被一大堆专业名词给整懵了:什么以太网,互联网,MAC,IP,局域网,万维网,网络分层模型等等等等。慢着!我学的不是以太网吗?怎么出来这么一大堆东西? 啊!以太网究竟是什么?别急,我接下来就尽量用通俗的大白话来给你解释…

Phpstudy 2018 之xhcms搭建

1、由于直接访问根目录无法进入网站 2、所以采用搭建网站&#xff0c;第一使用系统服务模式、选择php-5.4.45Apache模式 3、网站域名为本地ip地址或者127.0.0.1、端口8085 4、浏览器输入127.0.0.1:8085直接转到系统安装 5、返回输入127.0.0.1:8085&#xff0c;成功进入网站

前端JS特效第36波:jQ多种相册切换效果

jQ多种相册切换效果&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"h…

Mac安装stable diffusion 工具

文章目录 1.安装 Homebrew2.安装 stable diffusion webui 的依赖3.下载 stable diffusion webui 代码4.启动 stable diffusion webui 本体5.下载模型6.这里可能会遇到一个clip-vit-large-patch14报错 参考&#xff1a;https://brew.idayer.com/install/stable-diffusion-webui/…

[ruby on rails]部署时候产生ActiveRecord::PreparedStatementCacheExpired错误的原因及解决方法

一、问题&#xff1a; 有时在 Postgres 上部署 Rails 应用程序时&#xff0c;可能会看到 ActiveRecord::PreparedStatementCacheExpired 错误。仅当在部署中运行迁移时才会发生这种情况。发生这种情况是因为 Rails 利用 Postgres 的缓存准备语句(PreparedStatementCache)功能来…

数学建模·非线性规划

整型规划 适用于一个变量或多个变量的值只能是整型的情况 整形规划的分类 0-1背包问题 对于一个物品来说&#xff0c;只有选和不选两种情况 表现为单下标&#xff0c;单变量问题 例&#xff1a;建设学校问题 对于每个学校来说只有选和不选两种情况&#xff0c;在数学上我们用…

内网信息收集——MSF信息收集浏览器记录配置文件敏感信息

文章目录 一、配置文件敏感信息收集二、浏览器密码&记录三、MSF信息收集 域控&#xff1a;windows server 2008 域内机器&#xff1a;win7 攻击机&#xff1a;kali 就是红日靶场&#xff08;一&#xff09;的虚拟机。 一、配置文件敏感信息收集 使用searchall64.exe&#…

Windows11终端winget配置

一、工具安装 Windows11是自带该工具的&#xff0c;如果wind10&#xff0c;可以找应用商店和GitHub上进行下载。 安装地址使用 winget 工具安装和管理应用程序 | Microsoft Learn 发布地址 Releases microsoft/terminal GitHub 二、无法使用问题排错 在命令行界面出现以…

【python学习】多线程编程的背景、定义、特点、优缺点、使用场景和示例以及和单线程的区别

引言 随着计算机技术的发展&#xff0c;多核处理器已经成为了主流,为了充分利用多核处理器带来的并行计算能力&#xff0c;提高程序的执行效率和响应速度&#xff0c;多线程编程变得尤为重要 Python作为一种高级编程语言&#xff0c;提供了多线程编程的支持&#xff0c;允许开发…

电子期刊制作实战教程:从零开始制作

​随着互联网的普及&#xff0c;电子期刊已经成为了信息传递的重要载体。它以便捷、环保、互动性强等特点受到了越来越多人的青睐。那么&#xff0c;如何从零开始制作一份吸引人的电子期刊呢&#xff1f; 1.要制作电子杂志,首先需要选择一款适合自己的软件。比如FLBOOK在线制作…

链表(一)----单链表,链表的删除,链表的合并,链表的划分,头节点

官网地址&#xff1a;https://www.dhcode.cn/p/t_pc/goods_pc_detail/goods_detail/term_624bd804b3d39_Ac0g7V?fromH5true&type3&channel_id&pro_idterm_624bd804b3d39_Ac0g7V 本内容大部分从中截图 讲了三个力扣题&#xff1a;203&#xff0c;21&#xff0c;8…

【postgresql】锁

PostgreSQL 提供了多种锁模式来控制对表和行的并发访问&#xff0c;以确保数据的一致性和完整性。这些锁模式包括表级锁和行级锁&#xff0c;它们可以由应用程序显式控制&#xff0c;也可以在执行大多数 PostgreSQL 命令时自动获取。 锁类型 PostgreSQL类型的锁包括&#xff…

2024-07-14 Unity插件 Odin Inspector1 —— 插件介绍

文章目录 1 介绍2 模块3 学习目的 1 介绍 ​ Odin Inspector 是 Unity 的一个插件&#xff0c;拥有强大、自定义和用户友好的编辑器&#xff0c;而无需编写任何自定义编辑器代码&#xff0c;使得编程过程中的数据可视化更容易实现。 ​ 具体功能包括&#xff1a; 更舒适美观…

网络(二)——套接字编程

文章目录 理解源IP地址和目的IP地址认识端口号认识TCP/UDP协议网络字节序socket编程接口socket 常见APIsockaddr结构 理解源IP地址和目的IP地址 在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址&#xff1b; 源IP即发送方的地址&#xff0c;目的IP即接受方的…

创建yaml文件并读取

yaml文件可以存放token数据&#xff0c;那怎么操作存放并读取呢&#xff1f; 1、创建yaml文件 1、导入类库 import yaml 注意要导入的类库&#xff0c;在解释器中叫pyaml 2、创建文件 #创建yaml文件 yamlfileopen("testdata.yaml",w,encodingutf-8) 3、设置数据…

PostgreSQL 中如何解决因频繁的小事务导致的性能下降?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中解决因频繁小事务导致性能下降的方法 PostgreSQL 中解决因频繁小事务导致性能下降的方法…

电气工程VR虚拟仿真实训平台以趣味化方式增强吸引力

在工业4.0时代和教育信息化的双重推动下&#xff0c;我们致力于推动实训课件的跨界合作与共创。VR实训课件不仅促进了不同领域、不同行业之间的紧密合作&#xff0c;更让学习变得生动直观。我们凭借3D技术生动、直观、形象的特点&#xff0c;开发了大量配套3D教材&#xff0c;让…

如何允许从互联网(外网)进入路由器管理页面

1.绑定UDP端口 操作如图所示&#xff1a; 2.然后再绑定虚拟换回网卡 3.然后再把出端口编号设置成为2 使他成为一个双向输入输出具体操作如图所示&#xff1a; 4.进入防火墙然后再启动防火墙进行端口配置&#xff1a; 1.进入端口g0/0/0配置ip地址&#xff08;注意配置的ip地…

游戏热更新——AssetBundle

AssetBundle AssetBundle的定义与使用 AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至是整个场景&#xff0c;可以在游戏运行的时候被加载 AssetBundle自身保存着相互的依赖关系 压缩包可以使用LZMA和LZ4压缩算法&#xff0c;减少包大小&#xff0c;更快的进行网…

第五天安全笔记(持续更新)

第五天防御笔记 NAT种类&#xff1a; 静态NAT动态NATNapt 特点&#xff1a; 一对多----easy ip 多对多的napt 服务器的映射关系: 1.源NAT----基于IP地址进行转换&#xff0c;包括静态NAT&#xff0c;动态NAT&#xff0c;以及NAPT 2.目标NAT---基于目标IP地址进行转换&a…