之前也做过关于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、记录实体
public class ExcelList {
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.*;
@RestController
public class ExportExcelController {
@Autowired
private ExportExcel exportExcel;
public static List<ExcelList> list = new ArrayList<>(10);
@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 {
@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 {
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);
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 获取源码。
|