Java多线程导入Excel示例

news/2024/7/21 3:51:11 标签: java, excel, 开发语言

在导入Excel的时候,如果文件比较大,行数很多,一行行读往往速度比较慢,为了加快导入速度,我们可以采用多线程的方式
话不多说直接上代码
首先是Controller

java">import com.sakura.base.service.ExcelService;
import com.sakura.common.api.ApiResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

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

    @Autowired
    private ExcelService excelService;

    @PostMapping("/import")
    public ApiResult<Boolean> importExcel(@ModelAttribute MultipartFile file) throws Exception {
        boolean flag = excelService.importExcel(file);
        return ApiResult.result(flag);
    }
}

然后Service

java">import org.springframework.web.multipart.MultipartFile;

public interface ExcelService {

    boolean importExcel(MultipartFile file) throws Exception;

}

ServiceImpl

java">import com.sakura.base.entity.User;
import com.sakura.base.mapper.UserMapper;
import com.sakura.base.service.ExcelService;
import lombok.extern.java.Log;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
@Log
public class ExcelServiceImpl implements ExcelService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean importExcel(MultipartFile file) throws Exception {
        // 文件为空这些校验大家自己加,这里只是做一个示例

        // 每次处理的数据量,大家可以自己调整,比如每次处理1000条
        int batchSize = 5;
        // 最大线程数,大家可以自己调整,根据自己服务器性能来调整
        int maxThreads = 3;

        // 创建一个线程池并设置最大线程数
        ExecutorService executorService = Executors.newFixedThreadPool(maxThreads);
        Workbook workbook = null;
        try {
            workbook = new XSSFWorkbook(file.getInputStream());

            // 获取第一页
            Sheet sheet = workbook.getSheetAt(0);
            // 获取总行数
            int rowCount = sheet.getLastRowNum();

            // 第0行一般为表头,从第一行开始
            int startRow = 1;
            // 结束行,Math.min用来比较两个数的大小,取最小值
            int endRow = Math.min(batchSize, rowCount);

            while (startRow <= rowCount) {
                // 提交任务到线程池
                executorService.execute(new ExcelRowProcessorTask(sheet, startRow, endRow));

                // 下一批数据的起始行
                startRow = endRow + 1;
                // 下一批数据的结束行
                endRow = Math.min(startRow + batchSize - 1, rowCount);
            }

            // 关闭线程池
            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return true;
    }

    private class ExcelRowProcessorTask implements Runnable {
        private final Sheet sheet;
        private final int startRow;
        private final int endRow;

        public ExcelRowProcessorTask(Sheet sheet, int startRow, int endRow) {
            this.sheet = sheet;
            this.startRow = startRow;
            this.endRow = endRow;
        }

        @Override
        public void run() {

            // _________________________________________
            // 测试用,模拟处理数据的耗时,实际应用删除
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // _________________________________________

            for (int i = startRow; i <= endRow; i++) {
                Row row = sheet.getRow(i);
                if (row != null) {
                    Cell nameCell = row.getCell(0); // 第一列
                    Cell phoneCell = row.getCell(1); // 第二列

                    nameCell.setCellType(CellType.STRING);
                    String name = nameCell.getStringCellValue();

                    phoneCell.setCellType(CellType.STRING);
                    String phoneNumber = phoneCell.getStringCellValue();

                    User user = new User();
                    user.setName(name);
                    user.setPhoneNumber(phoneNumber);

                    userMapper.insert(user);
                }
            }
        }
    }
}

实体类User就不贴了没啥好说的

还有就是poi的jar包

		<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.15</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.15</version>
        </dependency>

用postman验证上面的代码

在这里插入图片描述

可以看下数据库的数据,因为我限制了每次处理的数据为5条,同时最多有3个线程,所以可以看到同一时间段导进去的数据为15条

在这里插入图片描述

上面这个还有一个问题就是主线程不会等数据导入完就会返回,如果你需要主线程等待数据导入完可以加上下面这行代码

java">executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // 等待所有任务执行完毕 Long.MAX_VALUE为超时时间,可以自由设置

就放在关闭线程池后面就可以了

在这里插入图片描述

有想看下怎么用多线程导出Excel的移步 Java多线程导出Excel示例


http://www.niftyadmin.cn/n/5407242.html

相关文章

ArcGIS学习(十)城市用地对比分析

ArcGIS学习(十)城市用地对比分析 1.城市用地变更分析 本任务给大家带来的内容是城市用地对比分析,包括两个关卡:城市用地变更分析 用地规划方案实施评价 城市用地变更分析和用地规划方案实施评价是我们进行用地分析时常见的两种场景。其中:城市用地变更分析主要是对不同…

(七步走写摘要): UserInformation bottleneck fusion for deep multi-view clustering

原摘要: Multi-view clustering aims to employ semantic information from multiple perspectives to accomplish the clustering task. However, a crucial concern in this domain is the selection of distinctive features. Most existing methods map data into a single…

【国产MCU】-CH32V307-实时时钟(RTC)

实时时钟(RTC) 文章目录 实时时钟(RTC)1、实时时钟(RTC)介绍2、RTC驱动API介绍3、RTC使用实例RTC 实时时钟是一组32 位可编程计数器,时基支持20 位预分频,用于较长时间段的测量。时钟基准来源高速的外部时钟128分频(HSE/128)、外部晶体低频振荡器(LSE)或内部低功耗RC…

linux小记(1)

基本概念&#xff1a;不依靠扩展名来区分文件类型 好处&#xff1a;除了文本文件其他所有windows文件都无法在Linux下运行&#xff0c;包括病毒木马。 坏处&#xff1a;所有的软件都需要对linux单独开发 习惯用后缀来区分文件&#xff0c;方便管理。 -压缩包&#xff1a;*.…

tomcat nginx 动静分离

实验目的:当访问静态资源的时候&#xff0c;nginx自己处理 当访问动态资源的时候&#xff0c;转给tomcat处理 第一步 关闭防火墙 关闭防护 代理服务器操作&#xff1a; 用yum安装nginx tomcat &#xff08;centos 3&#xff09;下载 跟tomcat&#xff08;centos 4&#xff0…

npm、cnpm、pnpm使用详细

简介&#xff1a; npm&#xff1a;npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理工具&#xff0c;用于安装、更新、卸载Node.js的模块和包。它提供了一个命令行界面&#xff0c;使得开发者可以轻松地管理项目依赖。npm 是 nodejs 中的一部分&#xff0c;…

Socket Select实战详解 - 构建高效网络通信模型

在现代网络编程中&#xff0c;select 是一个至关重要的系统调用&#xff0c;尤其在处理多连接场景时&#xff0c;它能有效地监控多个套接字上的读写事件&#xff0c;从而实现异步I/O。本文将带您逐步深入理解和实战 select 函数在 C 语言中的使用&#xff0c;从基本概念到实际应…

1.3 有哪些文本表示模型?它们各有什么优缺点?

1.3 有哪些文本表示模型?它们各有什么优缺点? 场景描述 文本是一类非常重要的非结构化数据&#xff0c;如何表示文本数据一直是机器学习领域的一个重要研究方向。 知识点 词袋模型(Bag of Words)TF-IDF(Term Frequency-Inverse DocumentFrequency)主题模型(Topic Model)词…