Java多线程导出Excel示例

news2024/9/25 19:20:31

在之前的Java多线程导入Excel示例中演示了如何通过多线程的方式导入Excel,下面我们再来看下怎么通过多线程的方式导出Excel
还是直接上代码
首先是Controller

import com.sakura.base.service.ExcelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

    @Autowired
    private ExcelService excelService;

    @GetMapping("/export")
    public void exportExcel(HttpServletRequest request, HttpServletResponse response) throws Exception {
        excelService.exportExcel(request, response);
    }
}

然后Service

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface ExcelService {

    void exportExcel(HttpServletRequest request, HttpServletResponse response) throws Exception;

}

还有ServiceImpl

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Service
@Log
public class ExcelServiceImpl implements ExcelService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void exportExcel(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 创建一个Excel文件,放在这里可以不用手动关闭流
        try (Workbook workbook = new XSSFWorkbook()) {
            // 创建一个Excel页
            Sheet sheet = workbook.createSheet("users");
            // 创建表头
            Row headerRow = sheet.createRow(0);
            // 给表头创建单元格并赋值
            headerRow.createCell(0).setCellValue("姓名");
            headerRow.createCell(1).setCellValue("手机号");
            headerRow.createCell(2).setCellValue("导出日期");

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

            // 创建线程池
            ExecutorService executorService = Executors.newFixedThreadPool(maxThreads);

            // 查询总记录数
            int totalCount = userMapper.selectCount(null);
            // 计算总批次
            int totalBatches = (int) Math.ceil((double) totalCount / batchSize);

            // 分批次导出数据
            for (int i = 0; i < totalBatches; i++) {
                int offset = i * batchSize;
                // 提交任务
                executorService.execute(new ExcelWriterTask(sheet, offset, batchSize));
            }

            // 关闭线程池
            executorService.shutdown();
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // 等待所有任务执行完毕 Long.MAX_VALUE为超时时间,可以自由设置

            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-disposition", "attachment;filename=users.xlsx");
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private class ExcelWriterTask implements Runnable {
        private Sheet sheet;
        private int offset;
        private int batchSize;

        public ExcelWriterTask(Sheet sheet, int offset, int batchSize) {
            this.sheet = sheet;
            this.offset = offset;
            this.batchSize = batchSize;
        }

        @Override
        public void run() {

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

            // 查询数据
            List<User> users = userMapper.selectList(new QueryWrapper<User>().orderByAsc("id").last("limit " + offset + ", " + batchSize));
            // 这里要注意,写入数据的时候需要同步写入,不然会出现覆盖等问题
            synchronized (sheet) {
                int rowNum = sheet.getLastRowNum();
                for (User user : users) {
                    Row row = sheet.createRow(++rowNum);
                    row.createCell(0).setCellValue(user.getName());
                    row.createCell(1).setCellValue(user.getPhoneNumber());
                    // 加个日期是为了好验证多线程导出的结构
                    row.createCell(2).setCellValue(new Date().toString());
                }
            }
        }
    }

}

实体类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>

测试一下接口

在这里插入图片描述

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

在这里插入图片描述

这里也有个问题,细心的人可能已经发现了,在写入的时候其实我加了synchronized关键字,这也导致了所有线程都必须等待其他线程完成写入操作后才能进行自己的写入操作,从而将并发写入转变为了串行写入,这似乎与多线程的使用相违背,这这种想法是对的,但是目前我也没想到更好的方法来控制多个线程同时写入的问题,当然这样写还是有用上多线程加快处理速度的特性的,毕竟在数据处理阶段,本来一条数据就要处理2秒,现在3个线程2秒可以同时处理3条数据,至于写入的那点时间其实可以忽略不计。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue中如何实现条件渲染?

在Vue中实现条件渲染非常简单且灵活&#xff0c;主要通过Vue的指令来实现。在Vue中&#xff0c;我们可以使用v-if和v-else指令来根据条件来渲染不同的内容。下面就让我们通过一个简单的示例来演示如何在Vue中实现条件渲染&#xff1a; <!DOCTYPE html> <html lang&qu…

Unity安装与简单设置

安装网址&#xff1a;https://unity.cn 设置语言&#xff1a; 设置安装位置&#xff1a;否则C盘就会爆了 获取一个个人的资格证&#xff1a; 开始安装&#xff1a; 安装完毕。 添加模块&#xff1a;例如简体中文 新建项目&#xff1a; 布局2*3、单栏布局、 设置…

2024有哪些免费的mac苹果电脑深度清理工具?CleanMyMac X

苹果电脑用户们&#xff0c;你们是否经常感到你们的Mac变得不再像刚拆封时那样迅速、流畅&#xff1f;可能是时候对你的苹果电脑进行一次深度清理了。在这个时刻&#xff0c;拥有一些高效的深度清理工具就显得尤为重要。今天&#xff0c;我将介绍几款优秀的苹果电脑深度清理工具…

飞书文档批量导出

背景需求 最近所参与的项目即将结项&#xff0c;需要将飞书中的产品需求文档&#xff08;PRD&#xff09;交付给甲方&#xff0c;由于文档较多&#xff0c;大概有两百多个&#xff0c;一个一个的下载导出&#xff0c;太麻烦了&#xff08;PS&#xff1a;本人比较懒&#xff09;…

【MySQL】mvcc以及三个重要日志

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;【】数据库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 MVCC关键概念&#xff1a; MVCC机制的优点&#xff1a; 三个重要的日志&#xff1a; 重做日志&#xff1a; 回滚日志&am…

智能汽车加速车规级存储应用DS2431P+TR 汽车级EEPROM 存储器IC

DS2431PT&R是一款1024位1-Wire EEPROM芯片&#xff0c;由四页存储区组成&#xff0c;每页256位。数据先被写入一个8字节暂存器中&#xff0c;经校验后复制到EEPROM存储器。该器件的特点是&#xff0c;四页存储区相互独立&#xff0c;可以单独进行写保护或进入EPROM仿真模式…

软考重点题解析-基础知识

1.加密技术&#xff1a;分为对称加密技术&#xff1a;文件的加密和解密使用相同的密钥 和 非对称加密技术&#xff1a;加密和解密不同的密钥&#xff0c;分别是公开密钥和私有密钥。 例题&#xff1a;若A,B两人分别在认证机构&#xff08;CA&#xff09;M,N处获得证书&…

修改centos7的dns解决docker拉取镜像超时问题

近期在一台centos7的服务器上部署系统&#xff0c;拉取docker镜像时总是超时&#xff0c;如图所示。网上有教程说&#xff0c;可以修改操纵系统的dns地址&#xff0c;试了一下&#xff0c;果然搞定。 打开dns配置文件 sudo vi /etc/resolv.conf发觉里面的地址设为114.114.114…

自动粘贴与网址管理,让您的网络生活更便捷!“

在数字化世界中&#xff0c;网址和文本信息的复制粘贴已成为我们日常操作中的家常便饭。然而&#xff0c;频繁的手动操作不仅效率低下&#xff0c;还容易出错。想象一下&#xff0c;如果能有一种工具&#xff0c;只需一键之触&#xff0c;就能自动完成粘贴和网址管理&#xff0…

【树莓派系统配置+python3.8+环境配置踩坑点汇总】raspberrypi

最近又开始搞树莓派的深度学习模型。很多windows端的环境需要在树莓派上重新部署&#xff0c;中间出现了非常多的问题。主要以各种库的下载安装为主要。 首先&#xff0c;第一个问题&#xff1a; 树莓派系统烧录之后&#xff0c;默认apt一般需要升级看&#xff0c;而默认下载…

redis05 sprngboot整合redis

redis的Java客户端 整合步骤 添加redis的pom依赖 <!-- 引入redis依赖 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency><!-- 引入redis连…

整数和浮点数在内存中的存储(大小端字节序,浮点数的存取)

目录 1.整数在内存中的存储 2.大小端字节序和字节序判断 2.1什么是大小端&#xff1f; 2.2为什么会有大小端 3.浮点数在内存中的存储 3.1浮点数的存储 3.1.1 浮点数存的过程 3.1.2 浮点数取的过程 3.2 解析 3.3 验证浮点数的存储方式 1.整数在内存中的存储 整数的二进…

Tomcat部署Web服务器及基础功能配置

前言 Tomcat作为一款网站服务器&#xff0c;目前市面上Java程序使用的比较多&#xff0c;作为运维工人&#xff0c;有必要了解一款如何去运行Java环境的网站服务。 目录 一、Java相关介绍 1. Java历史 2. Java跨平台服务 3. Java实现动态网页功能 3.1 servelt 3.2 jsp …

javaWebssh酒店客房管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh酒店客房管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0…

适配器模式 详解 设计模式

适配器模式 适配器模式是一种结构型设计模式&#xff0c;其主要作用是解决两个不兼容接口之间的兼容性问题。适配器模式通过引入一个适配器来将一个类的接口转换成客户端所期望的另一个接口&#xff0c;从而让原本由于接口不匹配而无法协同工作的类能够协同工作。 结构 适配…

Python环境下一种改进的基于梯度下降的自适应短时傅里叶变换

在数字信号处理技术中&#xff0c;傅里叶变换及其逆变换是一种信号时频分析方法。该方法将信号的时域描述及频域描述联系在一起&#xff0c;时域信号可通过正变换转变为频域信号&#xff0c;频域信号可通过逆变换转变为时域信号进行分析。但傅里叶变换及其逆变换是一种信号的整…

Linux 学习笔记(8)

八、 启动引导 1 、 Linux 的启动流程 1) BIOS 自检 2) 启动 GRUB/LILO 3) 运行 Linux kernel 并检测硬件 4) 挂载根文件系统 5) 运行 Linux 系统的第一个进程 init( 其 PID 永远为 1 &#xff0c;是所有其它进程的父进程 ) 6) init 读取系统引导配置文件…

前端导出word文件的多种方式、前端导出excel文件

文章目录 纯前借助word模板端导出word文件 &#xff08;推荐&#xff09;使用模板导出 前端通过模板字符串导出word文件前端导出 excel文件&#xff0c;node-xlsx导出文件&#xff0c;行列合并 纯前借助word模板端导出word文件 &#xff08;推荐&#xff09; 先看效果&#xf…

官封弼马心何足,名注齐天意未宁

解法一&#xff1a; 设left为多&#xff0c;right为少 每次分裂满足; 所以; 定义函数num(n,k)&#xff0c;子问题为num(l,k&#xff09;和num(r,k)。 递归结束&#xff1a;不可以精确分裂 #include<iostream> #include<vector> #include<algorithm> us…

24款奔驰C260L升级原厂360全景影像 高清环绕的视野

360全景影像影像系统提升行车时的便利&#xff0c;不管是新手或是老司机都将是一个不错的配置&#xff0c;无论是在倒车&#xff0c;挪车以及拐弯转角的时候都能及时关注车辆所处的环境状况&#xff0c;避免盲区事故发生&#xff0c;提升行车出入安全性。星骏汇小许Xjh15863 3…