之前也做过关于Excel的导出案例,此次也是在其基础上进行改造升级:
https://www.bilibili.com/video/BV1kf4y1i761?p=5
但是之前的导出存在这么几个问题:
- 如果是数据量很大容易导致页面卡死(我曾导出30w条数据,直接导致OOM)
- 用户体验很糟糕,数据量一多就会等很久,而且用户没办法做别的事情。
- 每次点击导出都需要走一遍完整的导出过程(这个其实还好)
- 没办法对每次导出的数据进一个规整
今天使用异步导出来解决上述问题。
一、UML图
1-1、导出图
1-2、下载图
从上面的图中可以看出,整个下载是异步的,用户不需要在页面等待,每次导出我们都生成一个记录和一个文件,用户可以多次下载。
二、功能实现
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导出** @author 小道仙97* @date 2021-08-08*/
@RestController
public class ExportExcelController {@Autowiredprivate 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 下载开始时间*/@Asyncvoid asyncExportExcel(String id,String name,Long startTime);
}
TestExportExcelImpl
@Service
public class TestExportExcelImpl implements ExportExcel {@Overridepublic 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导出文件流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 获取源码。