1、大数据量导出方案介绍
在SpringBoot中,可以使用MyBatis-Plus的流式查询功能实现大数据量的导出,并通过压缩文件的方式减小文件大小,提升导出效率。
具体实现步骤如下:
-
配置MyBatis-Plus的分页插件和流式查询插件。
-
创建一个Controller方法,接收客户端的请求,并使用流式查询功能查询出需要导出的数据。
-
将查询出的数据写入到Excel文件中,并使用Java原生的压缩类库将Excel文件压缩为zip文件。
-
将压缩后的文件作为响应内容,发送给客户端。
2、实际运用代码实践
下面是一个示例代码,演示了如何使用SpringBoot MyBatisPlus分页查询、压缩文件、导出大数据量的功能:
@GetMapping("/exportOrders")
public ResponseEntity<byte[]> exportOrders() throws IOException {
// 定义信息
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(out);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(gzipOut));
String header = "id,address,launchName,orderNum,orderRemark";
writer.write(header);
writer.newLine();
// 设置每页大小
int pageNum = 1;
int pageSize = 2000;
boolean hasNextPage = true;
// 分页查询需要导出的数据
while (hasNextPage) {
Page<RbgtOrder> page = new Page<>(pageNum, pageSize);
IPage<RbgtOrder> orderPage = orderMapper.selectPage(page, null);
List<RbgtOrder> orderList = orderPage.getRecords();
System.out.println("当前页数-> pageNum:" + pageNum + ",总页数:pages:" + orderPage.getPages() + "");
if (CollectionUtils.isNotEmpty(orderList)) {
for (RbgtOrder order : orderList) {
String line = order.getId() + "," + order.getAddress() + "," + order.getLaunchName() + "," + order.getOrderNum() + "," + order.getOrderRemark();
writer.write(line);
writer.newLine();
}
}
pageNum++;
if (pageNum == orderPage.getPages()) {
hasNextPage = false;
}
}
writer.flush();
writer.close();
gzipOut.finish();
byte[] bytes = out.toByteArray();
// 生成对应压缩文件到制定目录(后续可以结合导出中间件,供客户端下载 -> 适用于大数据量导出,没问题)
InputStream inputStream = new ByteArrayInputStream(bytes);
MultipartFile file = new MockMultipartFile(ContentType.OCTET_STREAM.toString(), inputStream);
file.transferTo(new File(getResourcesPath() + "orders.csv.gz"));
// 请求页面输出压缩文件(适用于小数据量导出,没问题)
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", "orders.csv.gz");
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
/**
* 查询 - 实时获取resources实时新增的文件目录
*
* @param
* @return java.lang.String
* @Author 俞春旺
* @Date 下午 07:29:28 2023年3月30日 0030
**/
public static String getResourcesPath() {
// 这里需要注意的是ApplicationHome是属于SpringBoot的类
// 获取项目下resources/static/img路径
ApplicationHome applicationHome = new ApplicationHome(RbgtOrderController.class);
// 保存目录位置根据项目需求可随意更改 - win和linux目录不一样
String path = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() + "/src/main/resources/temp/";
System.out.println("path:" + path);
return path;
}
在这个示例代码中,我们使用了MyBatis-Plus的lambdaQuery方法进行了分页查询,同时使用了流式查询功能避免了内存占用过大的问题。在每次查询一定数量的数据后,我们将数据写入Excel文件并将Excel文件写入到临时文件中。最后,我们将临时文件压缩为zip文件并将其作为响应内容发送给客户端。
需要注意的是,这里使用了Java原生的压缩类库,并且每次只压缩一定数量的数据,以避免占用过多的内存和文件系统资源。如果需要导出的数据量非常大,建议考虑使用专门的压缩库或者将数据存储到分布式文件系统中。
其实说白了,就是时间换空间,后续可以结合消息中间件或者中间导出服务,将压缩文件上传到自己服务器,在通过客户端下载链接即可