多人同时导出 Excel 干崩服务器?我们来实现一个排队导出功能!

考虑到数据库数据日渐增多,导出会有全量数据的导出,多人同时导出可以会对服务性能造成影响,导出涉及到mysql查询的io操作,还涉及文件输入、输出流的io操作,所以对服务器的性能会影响的比较大;

结合以上原因,对导出操作进行排队;

刚开始拿到这个需求,第一时间想到就是需要维护一个FIFO先进先出的队列,给定队列一个固定size,在队列里面的人进行排队进行数据导出,导出完成后立马出队列,下一个排队的人进行操作;

还考虑到异步,可能还需要建个文件导出表,主要记录文件的导出情况,文件的存放地址,用户根据文件列表情况下载导出文件。

业务关系定义

分别是用户、导出队列、导出执行方法

  • ExportQueue: 维护一条定长队列,可以获取队列里前后排队的用户,提供查询,队列如果已经满了,其余的人需要进行等待

  • User信息: 排队执行导出方法对应用户;

  • Export类: 定义导出方法,异步执行,用户可以通过导出页面查看、下载,导出的文件;

图片

具体代码实现

ExportQueue队列
package com.example.system.config;import com.example.system.api.domain.ExportUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.util.LinkedList;@Slf4j
@Component
public class ExportQueue {private final int MAX_CAPACITY = 10; // 队列最大容量private LinkedList<ExportUser> queue; // 用户队列public ExportQueue(LinkedList<ExportUser> queue) {this.queue = new LinkedList<>();}/*** 排队队列添加* @param sysUser*/public synchronized LinkedList<ExportUser> add(ExportUser sysUser) {while (queue.size() >= MAX_CAPACITY) {try {log.info("当前排队人已满,请等待");wait();} catch (InterruptedException e) {e.getMessage();}}queue.add(sysUser);log.info("目前导出队列排队人数:" + queue.size());notifyAll();return queue;}/*** 获取排队队列下一个人* @return*/public synchronized ExportUser getNextSysUser() {while (queue.isEmpty()) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}ExportUser sysUser = queue.remove();notifyAll(); //唤醒return sysUser;}
}
AbstractExport导出类

引入EasyExcel百万级别的导出功能

package com.example.system.config;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.PageUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.example.system.api.domain.ExportUser;
import lombok.extern.slf4j.Slf4j;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;@Slf4j
public abstract class AbstractExport<T, K> {public abstract void export(ExportUser sysUser) throws InterruptedException;/*** 导出** @param response 输出流* @param pageSize 每页大小* @param t        导出条件* @param k        Excel内容实体类* @param fileName 文件名称*/public void export(HttpServletResponse response, int pageSize, T t, Class<K> k, String fileName) throws Exception {ExcelWriter writer = null;try {writer = getExcelWriter(response, fileName);//查询导出总条数int total = this.countExport(t);//页数int loopCount = PageUtil.totalPage(total, pageSize);BeanUtil.setProperty(t, "pageSize", pageSize);for (int i = 0; i < loopCount; i++) {//开始页BeanUtil.setProperty(t, "pageNum", PageUtil.getStart(i + 1, pageSize));//获取Excel导出信息List<K> kList = this.getExportDetail(t);WriteSheet writeSheet = EasyExcel.writerSheet(fileName).head(k).build();writer.write(kList, writeSheet);}} catch (Exception e) {String msg = "导出" + fileName + "异常";log.error(msg, e);throw new Exception(msg + e);} finally {if (writer != null) {writer.finish();}}}public com.alibaba.excel.ExcelWriter getExcelWriter(HttpServletResponse response, String fileName) throws IOException {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileNameUtf = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileNameUtf + ".xlsx");return EasyExcel.write(response.getOutputStream()).build();}/*** (模版导出)** @param t* @param fileName* @param response*/public abstract void complexFillWithTable(T t, String fileName, HttpServletResponse response);/*** 查询导出总条数** @param t* @return*/public abstract int countExport(T t);/*** 查询导出数据** @param t* @return*/public abstract List<K> getExportDetail(T t);
}
ExportImpl导出实现方法
package com.example.system.service.impl;import com.alibaba.excel.ExcelWriter;
import com.example.system.api.domain.ExportUser;
import com.example.system.config.AbstractExport;
import com.example.system.config.ExportQueue;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;@Service
@Slf4j
public class ExportImpl extends AbstractExport {@Autowiredprivate ExportQueue exportQueue;@Overridepublic void export(ExportUser sysUser) throws InterruptedException {//导出log.info("导出文件方法执行~~~~~~~~~");
//        export(response,pageSize,t,k,fileName);LinkedList<ExportUser> queue = exportQueue.add(sysUser);log.info("导出队列:" + queue);//休眠时间稍微设置大点,模拟导出处理时间Thread.sleep(20000);//导出成功后移除当前导出用户ExportUser nextSysUser = exportQueue.getNextSysUser();log.info("移除后获取下一个排队的用户: " + nextSysUser.getUserName());}@Overridepublic void export(HttpServletResponse response, int pageSize, Object o, Class k, String fileName) throws Exception {super.export(response, pageSize, o, k, fileName);}@Overridepublic ExcelWriter getExcelWriter(HttpServletResponse response, String fileName) throws IOException {return super.getExcelWriter(response, fileName);}@Overridepublic void complexFillWithTable(Object o, String fileName, HttpServletResponse response) {}@Overridepublic int countExport(Object o) {return 0;}@Overridepublic List getExportDetail(Object o) {return null;}
}
测试controller
package com.example.system.controller;import com.example.system.api.domain.ExportUser;
import com.example.system.api.domain.SysUser;
import com.example.system.service.impl.ExportImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/export")
@Slf4j
public class ExportController {@Autowiredprivate ExportImpl export;@PostMapping("/exportFile")public void exportFile() {new Thread(new Runnable() {@SneakyThrows@Overridepublic void run() {Thread thread1 = Thread.currentThread();ExportUser sysUser =new ExportUser();sysUser.setUserName(thread1.getName());export.export(sysUser);}}).start();}
}
测试结果

通过请求测试方法,限制了我们导出队列最大限制10次,队列场长度超过10次则无法进行继续提交;

图片

第一次请求和第二次请求,间隔10秒,第一个用户导出完成后出列,下一个排队用户在队列首位,在进行导出请求排在上一个用户后面;

图片

总结

⚠️其余的还未实现,导出文件的表的设计、oss文件上传、用户导出文件下载,还有高并发的场景下会不会出现什么问题,这些都还没有太考虑进去;

实现的方式应该挺多的,Redis的队列应该也是可以的,这里仅仅提供一个实现思路;

最后说一句(求关注!别白嫖!)

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

西软云XMS futurehotel/operate XXE漏洞复现

0x01 产品简介 西软云XMS是基于云平台数据中心开发的支持多酒店、多语言、多平台的酒店管理系统。致力于以新一代云架构为国内四,五星级中高端酒店提供灵活、高度整合酒店业务,助力酒店智能转型升级。 0x02 漏洞复现 西软云XMS /XopServerRS/rest/futurehotel/operate接口…

倾囊相授之性能分析思路

年轻的时候&#xff0c;经常听一些大会或者演讲。有些人说&#xff0c;思路逻辑非常重要。我那时就想&#xff0c;你肯定是瞎忽悠的&#xff0c;因为我怎么就没听懂你说的思路呢&#xff1f; 而现在轮到自己来写或者讲一些东西的时候&#xff0c;才发现他们说得很对&#xff0…

【论文阅读】深度学习在过冷沸腾气泡动力学分割中的应用

Application of deep learning for segmentation of bubble dynamics in subcooled boiling 深度学习在过冷沸腾气泡动力学分割中的应用 期刊信息&#xff1a;International Journal of Multiphase Flow 2023 级别&#xff1a;EI检索 SCI升级版工程技术2区 SCI基础版工程技术3区…

【Spring Cloud 进阶】OpenFeign 底层原理解析

参考文章 万字33张图探秘OpenFeign核心架构原理 | 三友SpringCloud OpenFeign源码详细解析Java 代理机制 OpenFeign 是一个精彩的使用动态代理技术的典型案例&#xff0c;通过分析其底层实现原理&#xff0c;我们可以对动态代理技术有进一步的理解。 目录 1. Feign 与 OpenFeig…

鸿蒙真有前景吗?是真是假?

直到“纯血鸿蒙”发布&#xff0c;才看清华为真正的布局&#xff0c;这一招实在是高明&#xff01; “纯血鸿蒙”发布之前&#xff0c;国内大批人唱衰华为&#xff0c;唱衰鸿蒙系统的生态&#xff0c;认为大概率会走诺基亚和微软的老路&#xff0c;没想到“纯血鸿蒙”一经推出…

Docker基础篇(五) dockerfile之基础内容

Dockerfile基础内容 1、每条保留字指令都必须大写字母且后面要跟随至少一个参数 –保留字&#xff1a;– FROM、 MAINTAINER 作者、维护者、 RUN、 EXPOSE 暴露、曝光 WORKDIR ENV ADD COPY VOLUME CMD ENTRYPOINT 进入点&#xff0c;入口 ONBUILD 2、指令按照从上到下&#x…

Machine Vision Technology:Lecture2 Linear filtering

Machine Vision Technology&#xff1a;Lecture2 Linear filtering Types of ImagesImage denoising图像去噪Defining convolution卷积的定义Key properties卷积的关键属性卷积的其它属性Annoying details卷积练习Sharpening锐化Gaussian KernelNoise噪声 分类Gaussian noise高…

Java图书管理系统---命令行

项目列表 Book包 Book类内包含book的基本属性 BookList类初始化图书列表并且提供图书的属性方法 User包 Administrator类 common类 operator包 功能接口 新增图书功能 借阅图书功能 删除图书功能 显示图书功能 查找图书功能 归还图书功能 结束释放资源功能 运行…

matlab实现不同窗滤波器示例

1 汉明窗低通滤波器 &#xff1a; 在Matlab中使用汉明窗设计低通滤波器可以通过fir1函数实现。汉明窗通常用于设计滤波器&#xff0c;可以提供更突出的频率特性。 下面是一个示例代码&#xff0c;演示如何在Matlab中使用汉明窗设计低通滤波器&#xff1a; % 定义滤波器参数 fs …

DOM 获取父子节点

DOM 是以树状结构排列的&#xff0c;所以父子关系是相对的&#xff0c;当li为我们的目标节点的时候&#xff0c;ul为其父节点&#xff0c;其他li为它的兄弟节点&#xff0c;li里面包含的标签为子节点&#xff0c;以此类推。 那我们如何找父节点&#xff1f; 元素.parentNode&am…

ROS2----运行helloworld、集成开发环境的搭建

前言&#xff1a;ROS2已经出来了&#xff0c;ROS1会被逐渐淘汰&#xff0c;大家尽量不要学ROS1了&#xff01;&#xff01; 文章目录 一、运行helloworld1.创建工作空间2.创建功能包3.源文件和配置文件4.编译与运行5.源码编写下的编译与运行6.运行优化 二、集成开发环境的搭建…

Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析

3. SpringBoot原理 SpringBoot使我们能够集中精力地去关注业务功能的开发&#xff0c;而不用过多地关注框架本身的配置使用。而我们前面所讲解的都是面向应用层面的技术&#xff0c;接下来我们开始学习SpringBoot的原理&#xff0c;这部分内容偏向于底层的原理分析。 在剖析Sp…

嵌入式中14 个超级牛的免费开源小工具

Homebrew for macOS 地址&#xff1a;https://brew.sh Mac 上非常好用的包管理工具&#xff0c;很多常见的安装都可以通过 brew install app 或者 brew cask install app 直接安装&#xff0c;类似 apt-get 。 Oh My Zsh 地址&#xff1a;https://github.com/robbyrussell…

基于springboot实现线上阅读系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现线上阅读系统演示 摘要 随着社会发展速度的愈来愈快&#xff0c;以及社会压力变化的越来越快速&#xff0c;致使很多人采取各种不同的方法进行解压。大多数人的稀释压力的方法&#xff0c;是捧一本书籍&#xff0c;心情地让自己沉浸在情节里面&#xff0c;以…

【2022 J1】乘方

本主又双叒叕来更新了&#xff0c;一圈三连不用说了吧&#x1f601; 本题是J组第二轮的题&#xff1a; 题目描述 小文同学刚刚接触了信息学竞赛&#xff0c;有一天她遇到了这样一个题&#xff1a;给定正整数 a 和 b&#xff0c;求 &#xfffd;&#xfffd;ab 的值是多少。 …

【iOS ARKit】协作 Session 实例

协作 Session 使用注意事项 协作 Session 是在 ARWorldMap 基础上发展起来的技术&#xff0c;ARWorldMap 包含了一系列的地标、ARAnchor 及在观察这些地标和 ARAnchor 时摄像机的视场&#xff08;View&#xff09;。如果用户在某一个位置新创建了一个 ARAnchor&#xff0c;这时…

DataGrip2023配置连接Mssqlserver、Mysql、Oracle若干问题解决方案

1、Mssqlserver连接 本人连的是Sql2008&#xff0c;默认添加时&#xff0c;地址、端口、实例、账号、密码后&#xff0c;测试连接出现错误。 Use SSL&#xff1a;不要勾选 VM option&#xff1a;填写&#xff0c;"-Djdk.tls.disabledAlgorithmsSSLv3, RC4, DES, MD5withR…

人工智能如何改变我们与世界的沟通的方式?

腾讯研究院 作为一名设计师、艺术家、科技研究人员,人工智能如何改变我们与世界的沟通的方式&#xff1f; 1.《音外话》 它是一款语音至视频生成人工智能的系统&#xff0c;它把我们的话语转化为充满情感的视觉影像。这个系统不仅可以捕捉语言的字面意义&#xff0c;还能理解…

小红书关键词爬虫

标题 1 统计要收集的关键词&#xff0c;制作一个文件夹2 爬取每一页的内容3 爬取标题和内容4 如果内容可以被查看&#xff0c;爬取评论内容5 将结果进行汇总&#xff0c;并且每个帖子保存为一个json文件&#xff0c;具体内容6 总结 1 统计要收集的关键词&#xff0c;制作一个文…

ts的重载

官网示例 TypeScript: Documentation - Template Literal Types 这里大概理解是 T 继承了Number|sting 加上&#xff1f;条件判断就是 T继承Number|sting 部分为true 没有继承部分为false&#xff0c; 就是输入string, 为true, 输入 null 则为false, type Exclude<T, U&…