Решение для экспорта больших данных в 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
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода