超好用的Excel异步导出功能

news/2024/7/21 5:08:44 标签: Excel导出, 导出, Excel

之前也做过关于Excel导出案例,此次也是在其基础上进行改造升级:

https://www.bilibili.com/video/BV1kf4y1i761?p=5

但是之前的导出存在这么几个问题:

  • 如果是数据量很大容易导致页面卡死(我曾导出30w条数据,直接导致OOM)
  • 用户体验很糟糕,数据量一多就会等很久,而且用户没办法做别的事情。
  • 每次点击导出都需要走一遍完整的导出过程(这个其实还好)
  • 没办法对每次导出的数据进一个规整

今天使用异步导出来解决上述问题。


一、UML图

1-1、导出

前台 Controller ServiceA ServiceB 点击导出 往数据库插入记录 插入一条下载记录 id name文件名 rows 下载行数 (null) takeUpTime 下载耗时 (null) downloadUrl 下载地址(null) 异步下载 (id、startTime) success 下载成功,稍等片刻去【下载中心】下载 根据需求去获取对应的数据 把数据生成一个文件保存起来 根据Id获取刚刚插入的记录 完善以下数据 rows 下载行数 takeUpTime 下载耗时 downloadUrl 下载地址(null) 前台 Controller ServiceA ServiceB

1-2、下载图

前台 Controller 获取下载列表 返回下载列表 downLoadUrl 返回文件流 前台 Controller

从上面的图中可以看出,整个下载是异步的,用户不需要在页面等待,每次导出我们都生成一个记录和一个文件,用户可以多次下载。


二、功能实现

2-1、记录实体

/**
 * Excel列表数据
 *
 * @author 小道仙97
 * @date 2021/8/8
 */
public class ExcelList {

    /**
     * id
     */
    private String id;

    /**
     * 文件名
     */
    private String name;

    /**
     * 下载行数
     */
    private Integer rows;

    /**
     * 下载耗时
     */
    private Long takeUpTime;

    /**
     * 下载地址
     */
    private String downloadUrl;
}

2-2、Controller

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * Excel导出>Excel导出
 *
 * @author 小道仙97
 * @date 2021-08-08
 */
@RestController
public class ExportExcelController {

    @Autowired
    private ExportExcel exportExcel;

    // 模仿下载列表
    public static List<ExcelList> list = new ArrayList<>(10);

    /**
     * Excel 导出
     * @throws Exception
     */
    @GetMapping("/excel/export")
    public void export() {
        Long startTime = System.currentTimeMillis();
        String name = "Excel异步导出测试" + UUID.randomUUID().toString() + ".xlsx";
        String id = UUID.randomUUID().toString();
        ExcelList excelList = new ExcelList();
        excelList.setId(id);
        excelList.setName(name);
        list.add(excelList);
        // 异步导出
        exportExcel.asyncExportExcel(id,name,startTime);

    }

    /**
     * 获取导出列表 - 模拟
     */
    @GetMapping("/excel/list")
    public List<ExcelList> list() {
       return list;
    }

    /**
     * 文件下载
     */
    @GetMapping("/excel/downLoad")
    public void downLoad(HttpServletResponse response,@RequestParam  String url) {
        FileUtils.download(url, response);
    }
}

2-3、异步下载实现

ExportExcel

注:使用异步注解@Async 需要先在启动类上开启 @EnableAsync

import org.springframework.scheduling.annotation.Async;

public interface ExportExcel {

    /**
     * 异步导出
     * @param id 唯一记录Id
     * @param name 文件名称
     * @param startTime 下载开始时间
     */
    @Async
    void asyncExportExcel(String id,String name,Long startTime);
}

TestExportExcelImpl

@Service
public class TestExportExcelImpl implements ExportExcel {

    @Override
    public void asyncExportExcel(String id,String name,Long startTime) {
        // 模拟查询数据过程
        String[] header = new String[]{"姓名","年纪"};
        String[] keys = new String[]{"name","age"};
        List<Map<String, Object>> content = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("name","小道仙");
        map1.put("age","23");
        content.add(map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("name","小道仙97");
        map2.put("age","97");
        content.add(map2);

        try {
            // 获取Excel导出>Excel导出文件流
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ExcelUtils.exportExcel(header,keys,content,"first",os);
            byte[] content1 = os.toByteArray();
            InputStream inputStream = new ByteArrayInputStream(content1);
            // 上传文件 返回下载地址
            String url = FileUtils.uploadInputStream(inputStream, name);
            /**
             * 找到当前数据并封装结果集
             *
             * 其实这里很简单并无这么复杂,实际情况我们只需要一个 update 语句就可以搞定
             */
            for (ExcelList item : ExportExcelController.list) {
                if (item.getId().equals(id)) {
                    item.setRows(content.size());
                    item.setDownloadUrl(url);
                    item.setTakeUpTime(System.currentTimeMillis() - startTime);
                    break;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

三、演示

下面的演示的前提都是在启动了项目的基础上

3-1、导出

因为没有做任何的返回值,所以是空返回,这里也可以自定义任何提示返回。

http://127.0.0.1:8888/excel/export


3-2、下载列表

http://127.0.0.1:8888/excel/list

返回结果如下:

[
    {
        "id": "d3cb3551-cb33-445e-8e60-9534197f6647",
        "name": "Excel异步导出测试80d50264-3930-4667-8bc5-2d4a1cfe0d9d.xlsx",
        "rows": 2,
        "takeUpTime": 5,
        "downloadUrl": "2021/8/8/Excel异步导出测试80d50264-3930-4667-8bc5-2d4a1cfe0d9d.xlsx"
    }
]

3-3、下载

http://127.0.0.1:8888/excel/downLoad?url=2021/8/8/Excel异步导出测试80d50264-3930-4667-8bc5-2d4a1cfe0d9d.xlsx



视频看讲解地址:https://www.bilibili.com/video/BV1kf4y1i761

关注微信公众号回复:xdxFrameSimple 获取源码。

在这里插入图片描述


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

相关文章

MySQL索引详解【B+Tree索引、哈希索引、全文索引、覆盖索引】

前段时间面试每次提到索引&#xff0c;我就巴拉巴拉说一堆&#xff0c;然后到了说说你理解的 Btree索引我就懵逼了。 直接说Btree可能并不是很好理解&#xff0c;下面我们从最简单的二叉查找树开始慢慢循序渐进。 一、BTree索引 1、二叉查找树 在最开始学习树的时候&#xf…

docker内安装vim、E: Unable to locate package vim、Could not connect to deb.debian.org:80

一 今天想在docker里面修改下MySQL的配置文件&#xff0c;使用 vim命令&#xff0c;发现没有。 二 按照网上的办法&#xff0c;运行下面两个命令&#xff0c;结果报错 Could not connect to deb.debian.org:80 apt-get update apt-get install -y vim看错误是说链接不上这个…

docker里面的MySQL无法启动,Mac进入docker(修改配置文件导致无法启动)【MAC、linux、windoc】

其实问题在于如何找到我们的那个配置文件&#xff0c;这里我修改的配置文件是 my.cnf 一、MAC mac下 docker 实际是在vm里又加了一层&#xff0c;因此需要进入 vm 才能进行操作&#xff0c;进入docker命令如下 screen ~/Library/Containers/com.docker.docker/Data/vms/0/tt…

Non-resolvable parent POM for Could not find artifact and ‘parent.relativePath‘ points at wrong loca

一、问题解决 在使用maven打包的时候&#xff0c;报了上面这个错&#xff0c;简单来说就是找不到某个依赖&#xff0c;这是因为我们在构建子父工程的时候&#xff0c;子类打包找不到父类的依赖。 一般我们只需要重新打开父类&#xff0c;然后执行 mvn install &#xff0c;再去…

细说InnoDB缓冲池 buffer pool(free、flush、lru)

视频地址 https://www.bilibili.com/video/BV1C3411t7WL 文章目录一、开篇二、free链表三、flush 链表四、LRU 链表全表扫描预读冷热区域五、数据回盘一、开篇 在InnoDB引擎中对数据库增删改查&#xff0c;都是先从磁盘中把数据加载到内存&#xff0c;然后在内存中进行相关操作…

使用Java处理大数据避坑指南

视频地址 https://www.bilibili.com/video/BV1MZ4y1S741 最近接到一个任务&#xff1a;对一大批数据进行处理&#xff0c;先使用接口把数据拉取到本地&#xff0c;然后再写脚本进行处理&#xff0c;数据量大概有几百万&#xff0c;所以单线程就不满足了。 处理逻辑其实不重要&…

SpringBoot使用异步无法获取自定义注解

一、前言 在SpringBoot项目中&#xff0c;我们要开启异步执行其实很简单&#xff0c;只需要2步 在启用类上加开启异步注解 EnableAsync在对应的方法或者类上面加入标示开启异步的注解 Async 二、问题 但是今天遇到一个问题&#xff0c;由于数据量的递增需把原来的方法改成异…

MyBatis/MyBatis-Plus 使用枚举参数异常, SpringBoot枚举参数异常

视频地址&#xff1a; https://www.bilibili.com/video/BV1kf4y1i761?p15 在开发中&#xff0c;有很多字段使用枚举类型可以更好地表达我们想要的效果。但在实际使用过程中&#xff0c;却存在两个问题 枚举参数映射到数据库的时候类型匹配不上接收枚举参数的时候也会存在结果…