Решение для экспорта больших данных в SpringBoot: используйте EasyExcel для параллельного экспорта нескольких файлов Excel, сжатия zip-архива и загрузки его.
Решение для экспорта больших данных в SpringBoot: используйте EasyExcel для параллельного экспорта нескольких файлов Excel, сжатия zip-архива и загрузки его.

В методе синхронного экспорта Excel SpringBoot служба будет заблокирована до тех пор, пока не будет создан файл Excel. Если экспортируется большой объем данных, эффективность будет низкой, а качество работы будет плохим. Эффективное решение — разделить экспортированные данные и использовать CompletableFuture для асинхронизации задачи экспорта, использовать easyExcel для параллельного экспорта нескольких файлов Excel и, наконец, сжать все файлы в формат ZIP для удобства загрузки.

На основе приведенного выше решения в среде Springboot следующий код может быть выполнен с высоким качеством для экспорта информации о заказе на продажу в файлы Excel, упаковки нескольких файлов Excel в ZIP-файл и, наконец, отправки его клиенту:

  1. Код слоя контроллера
Язык кода:javascript
копировать
@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 параллельно обрабатывает экспорт заказов на продажу.
Язык кода:javascript
копировать
@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<SalesOrder> 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-файла в ответ
    zipFileInputStream = Files.newInputStream(tempZipFilePath);
    IOUtils.copy(zipFileInputStream, response.getOutputStream());
   } catch (Exception e) {
    log.error("salesOrderExport,Exception:", e);
    throw new RuntimeException("Исключение экспорта, повторите попытку позже");
   } finally {
      try {  
         // закрыть поток
        if (Objects.nonNull(zipFileInputStream)) {
           zipFileInputStream.close();
         }    
        // Удалить временные файлы и каталоги
        if (Objects.nonNull(tempDir)) {
           Files.walkFileTree(tempDir, new SimpleFileVisitor<Path>() {
              @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);
    }
   } 
  • Экспортируйте каждый заказ на продажу в отдельный файл Excel на основе шаблона с помощью библиотеки EasyExcel.

Содержимое шаблона:

Язык кода:javascript
копировать
 /**
   * Экспортируйте один файл Excel, вызов многопоточного кода выше.
   **/
 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. Многопоточность
    • проходитьCompletableFutureиThreadPoolTaskExecutor,Распределите задачу экспорта заказов на продажу на несколько потоков для параллельного выполнения.,Значительно улучшена производительность при обработке больших заказов.
    • использоватьLists.partitionМетод разделения списка заказов на несколько подсписков,Каждый подсписок обрабатывается потоком,Здесь на каждые 5 заказов приходится одна тема.
  2. Экспорт шаблона Excel
    • Используя функцию шаблона EasyExcel, вы можете заполнять данные на основе предопределенных шаблонов Excel для создания файлов Excel с заказами на продажу в едином формате.
    • файл шаблонапроходитьзагрузчик классовgetResourceAsStreamзагрузка метода,Простота обслуживания.
    • Упакуйте несколько файлов Excel в ZIP-файл, чтобы пользователи могли их загружать и управлять ими.
  3. Очистка ресурсов
    • После выполнения метода поток открытых файлов своевременно закрывается, а временно созданные файлы и каталоги Excel удаляются во избежание утечки ресурсов.
    • использоватьtry-with-resourcesиtry-catch-finallyчтобы убедиться, что ресурс правильно закрытиубирать。
  4. Обработка ошибок
    • Во время выполнения метода возможные исключения фиксируются и обрабатываются, чтобы обеспечить надежность службы.
    • В случае неисправимых ошибок вызывающая сторона уведомляется путем создания исключения во время выполнения, а также записываются подробные журналы ошибок.
boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose