百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

SpringBoot中大量数据导出使用EasyExcel导出多个excel文件并压缩

liuian 2025-02-08 11:50 41 浏览

SpringBoot的同步excel导出方式中,服务会阻塞直到Excel文件生成完毕,如果导出数据很多时,效率低体验差。有效的方案是将导出数据拆分后利用CompletableFuture,将导出任务异步化,并行使用easyExcel导出多个excel文件,最后将所有文件压缩成ZIP格式以方便下载。

Springboot环境下基于以上方案,下面代码的高质量的完成导出销售订单信息到Excel文件,并将多个Excel文件打包成一个ZIP文件,最后发送给客户端:

  1. 控制器层代码
@RestController
public class SalesOrderController {

    @Resource
    private SalesOrderExportService salesOrderExportService;

   @PostMapping(value = "/salesOrder/export")
    public void salesOrderExport(@RequestBody @Validated RequestDto req, HttpServletResponse response) {
        salesOrderExportService.salesOrderExport(req, response);
    }
 
}
  1. 服务层代码

负责执行销售订单的导出逻辑:

  • 1. 将多个Excel文件打包成ZIP文件
  • 2. 多线程ThreadPoolTaskExecutor并行处理销售订单的导出
@Slf4j
@Service
public class SalesOrderExportService {
 
    @Autowired
    @Qualifier("threadPoolTask")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
 
    @Resource
    private OrderManager OrderManager;
 
 
 public void salesOrderExport(RequestDto req, HttpServletResponse response) {
  
   // 获取导出数据,每个SalesOrder实例需要分别导出到一个excel文件
   List orderDataList = OrderManager.getOrder(req.getUserCode());
   // 略...校验数据
   
   InputStream zipFileInputStream = null;
   Path tempZipFilePath = null;
   Path tempDir = null;
   // 获取导出模板
   try (InputStream templateInputStream = this.getClass().getClassLoader().getResourceAsStream("template/order_template.xlsx");
     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();) {
     
    if (Objects.isNull(templateInputStream)) {
     throw new RuntimeException("获取模版文件异常");
    }
    // 多线程服用一个文件流
    IOUtils.copy(templateInputStream, outputStream);
    
    // 创建临时excel文件导出目录,用于将多个excel导出到此目录下
    Path tmpDirRef = (tempDir = Files.createTempDirectory(req.userCode() + "dir_prefix"));
     
    // 每5个salesOrder一个线程并行导出到excel文件中
    CompletableFuture[] salesOrderCf = Lists.partition(orderDataList, 5).stream()
    .map(orderDataSubList -> CompletableFuture
      .supplyAsync(() -> orderDataSubList.stream()
        .map(orderData -> this.exportExcelToFile(tmpDirRef, outputStream, orderData))
        .collect(Collectors.toList()), threadPoolTaskExecutor)
      .exceptionally(e -> {throw new RuntimeException(e);}))
    .toArray(CompletableFuture[]::new);
   
    // 等待所有excel文件导出完成
    CompletableFuture.allOf(salesOrderCf).get(3, TimeUnit.MINUTES);
    
    // 创建临时zip文件
    tempZipFilePath = Files.createTempFile(req.userCode() + TMP_ZIP_DIR_PRE, ".zip");
    
    // 将excel目录下的所有文件压缩到zip文件中,zipUtil有很多工具包都有
    ZipUtil.zip(tempDir.toString(), tempZipFilePath.toString());
    
    response.setContentType("application/octet-stream;charset=UTF-8");
    response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(tempZipFilePath.toFile().getName(), "utf-8"));
    
    // 写zip文件流到response
    zipFileInputStream = Files.newInputStream(tempZipFilePath);
    IOUtils.copy(zipFileInputStream, response.getOutputStream());
   } catch (Exception e) {
    log.error("salesOrderExport,异常:", e);
    throw new RuntimeException("导出异常,请稍后重拾");
   } finally {
      try {  
         // 关闭流
        if (Objects.nonNull(zipFileInputStream)) {
           zipFileInputStream.close();
         }    
        // 删除临时文件及目录
        if (Objects.nonNull(tempDir)) {
           Files.walkFileTree(tempDir, new SimpleFileVisitor() {
              @Override
              public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                   Files.deleteIfExists(file);
                   return FileVisitResult.CONTINUE;
              }
             @Override
             public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                 Files.deleteIfExists(dir);
                 return FileVisitResult.CONTINUE;
              }
            });
        }
        if (Objects.nonNull(tempZipFilePath)) {
          Files.deleteIfExists(tempZipFilePath);
        }
    } catch (Exception e) {
        log.error("salesOrderExport, 关闭文件流失败:", e);
    }
   } 
  • 使用EasyExcel库基于模板导出每个销售订单到单独的Excel文件中


 /**
   * 导出单个excle文件,上面的多线程代码调用
   **/
 private Path exportExcelToFile(Path temporaryDir, ByteArrayOutputStream templateOutputStream, SalesOrder data) {
     Path temproaryFilePath = null;
     try {
         // 创建临时文件 
         temproaryFilePath = Files.createTempFile(temporaryDir, data.getOrderNo(), ExcelTypeEnum.XLSX.getValue());
     } catch (IOException e) {
         throw new RuntimeException("exportExcelToFile,创建excel临时文件失败:" + data.getOrderNo());
     }
     try (InputStream templateInputStream = new ByteArrayInputStream(templateOutputStream.toByteArray());
          OutputStream temporaryFileOs = Files.newOutputStream(temproaryFilePath);
          BufferedOutputStream tempOutStream = new BufferedOutputStream(temporaryFileOs)) {
    
        // 使用easyExcel的模板功能导出订单数据到临时文件中 
         ExcelWriter excelWriter = EasyExcel.write(tempOutStream, SalesOrder.class)
                 .withTemplate(templateInputStream).excelType(ExcelTypeEnum.XLSX).build();
   
         // 填充模板数据
         WriteSheet writeSheet = EasyExcel.writerSheet().build();
         FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
         excelWriter.fill(new FillWrapper("goods", data.getGoodsList()), fillConfig, writeSheet);
         excelWriter.fill(data, writeSheet);
         excelWriter.finish();
         // temproaryFilePath.toFile().deleteOnExit();
         return temproaryFilePath;
     } catch (Exception e) {
         throw new RuntimeException("exportExcelToFile,导出excel文件失败:" + data.getOrderNo(), e);
     }
 }
 


代码亮点分析

  1. 多线程处理
  2. 通过CompletableFuture和ThreadPoolTaskExecutor,将销售订单的导出任务分配给多个线程并行执行,显著提高了处理大量订单时的性能。
  3. 使用Lists.partition方法将订单列表分割成多个子列表,每个子列表由一个线程处理,这里每5个订单一个线程。
  4. Excel模板导出
  5. 利用EasyExcel的模板功能,可以基于预定义的Excel模板填充数据,从而生成格式统一的销售订单Excel文件。
  6. 模板文件通过类加载器的getResourceAsStream方法加载,便维护。
  7. 将多个Excel文件打包成一个ZIP文件,方便用户下载和管理。
  8. 资源清理
  9. 方法执行完毕后,及时关闭打开的文件流和删除临时生成的Excel文件和目录,避免了资源泄露。
  10. 使用try-with-resources和try-catch-finally来确保资源的正确关闭和清理。
  11. 错误处理
  12. 在方法执行过程中,对可能出现的异常进行了捕获和处理,确保服务的健壮。
  13. 对于无法恢复的错误,通过抛出运行时异常的方式通知调用者,并记录了详细的错误日志。

相关推荐

亲手自己重装系统win7(自己怎么重装win7)

要一键安装重装系统Win7,您可以使用Windows7安装盘或USB驱动器。首先,将安装盘或USB插入计算机,并重启计算机。然后,在计算机启动时按下相应的按键(通常是F12或Del键)进入启动菜单。...

windows7旗舰版临时激活(win7暂时激活)

关于这个问题,目前,有几种方法可以激活Windows7旗舰版,以下是最简单的几种方法:1.使用激活工具:可以使用一些第三方激活工具,如KMSpico、MicrosoftToolkit等工具来激活...

免费查序列号入口(免费查序列号入口平板)

苹果查序列号入口可登陆苹果官网checkcoverage.apple.com进行查询,具体步骤如下:1、打开手机设置,点击“通用”;2、进入页面后点击“关于本机”;3、页面跳转后,我们就可以看到本机的...

磁盘被保护了如何取消保护(磁盘被保护了如何取消保护设置)

1、打开磁盘分区管理窗口中选择要去掉被写保护的磁盘。2、选中磁盘后单击鼠标右键可显示出选项列表下选择属性。3、打开磁盘属性对话框中选择点击硬件选项卡。4、然后在硬件页面中选中所有磁盘后再单击属性按钮。...

win7系统硬盘分区教程(win7如何对硬盘分区)

在Win7中,你可以使用磁盘管理工具来给硬盘分区。首先,打开控制面板,点击“系统和安全”,然后选择“管理工具”。在管理工具中,找到“计算机管理”,点击打开。在计算机管理窗口中,选择“磁盘管理”。在磁盘...

电脑不识别移动硬盘怎么办(笔记本电脑不识别移动硬盘怎么办)

电脑无法识别移动硬盘的原因有很多,以下是一些可能的原因和相应的解决方法:1.USB供电不足:移动硬盘功率较大,可能需要更多的电压。前置USB接口可能无法提供足够的电压。解决方法是将移动硬盘接到...

cf穿越火线烟雾头盔怎么调(cf的最新烟雾头盔怎么调)

cf新版烟雾保护头盔调置:?cf这款游戏中,更新后调整烟雾头的方法是打开NVIDIA控制面板,在NVIDIA控制面板中选择调整视频颜色设置,接着点击通过NVIDIA设置选项,然后将亮度调整到79%,对...

u盘怎样格式化最安全(u盘怎么格式化最干净)

只需将U盘插入到电脑之后,然后在我的电脑中找到U盘的盘符,使用鼠标右键点击打开菜单,其中就可以看到【格式化】的选项,根据需要选择然后点击【快速格式化】即可U盘格式是FAT32格式,那么其传输速度会明显...

移动路由器怎么改wifi密码(移动网络路由器怎么改密码wifi密码)
移动路由器怎么改wifi密码(移动网络路由器怎么改密码wifi密码)

1.打开手机设置,找到wifi点击进入,点击已连接的wifi。2.里面有一个路由器的选项,记住路由器后面一串数字。3.打开手机网页,在地址栏输入刚记住的那串数字,点击进入,选择继续访问网页版,输入管理员密码,点击确定。4.点击路由设置,点击...

2025-12-23 16:05 liuian

手机五笔输入法怎么使用(手机五笔怎么用新手教程)
手机五笔输入法怎么使用(手机五笔怎么用新手教程)

手机使用五笔输入法操作方法1、打开手机,点击应用商店,下载搜狗输入法,并安装。2、打开下载后的搜狗输入法,在打开页面勾选搜狗输入法,然后点击启用。3、在弹出页面,点击搜狗输入法。在编辑文字页面,点击如图所示按钮。4、在弹出页面,点击其他输入...

2025-12-23 15:55 liuian

天翼网关怎么设置wifi(天翼网关怎么设置wifi密码)

天翼网关设置wifi的方法步骤如下:首先打开浏览器,在地址栏中输入198.168.1.1,确定。输入用户名、密码,如果以前没改过,这个密码就在网关背面的标签上面,可以去查看一下,输入后点击“确定”。点...

十大软件免费下载安装(软件大全下载)

以下是十大永久免费电视直播软件APP:央视频(手机端)):官方看电视直播软件,画质清晰,需要借助手机投屏操作。央视投屏助手(盒子端):与央视频配合使用,提供高清电视直播。电视家:智能电视、电视盒子或智...

电脑死机咋办(电脑开机蓝屏怎么办)

可按照如下方式重启:1、直接按下“CTRL+ALT+DEL”键,然后选择重启;2、如方式1无效,可按住电源键数秒进行强制关机,然后再次启动即可;3、最后一个办法就是,拔出电池和电源适配器,然后重新安装...

追剧神器免费下载(苹果手机免费追剧软件)

是正规网站茶杯狐官方网站是一款正规的视频播放软件。茶杯狐官方网站拥有各种电影、电视剧、综艺、动漫等视频任由用户们在线自由观看。茶杯狐官方网站所有的视频画质也非常的超清流畅,很安全。茶杯狐软件是很好用的...

平板电脑一键root工具(平板电脑 root)

1、下载APP:ROOT大师;2、打开小米平板USB调试模式;3、安装驱动,提示连接成功4、获取ROOT权限。5、显示更新成功后依次选择:返回-重新启动-系统6、重启后打开桌面的super...