从OSS下载EXCEL模版,新增第一列。导出数据

public void exportErrorOrderList(HttpServletResponse response, String exportKey){
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        Locale currentLocale = Optional.of(LocaleContextHolder.getLocale()).orElse(Locale.ENGLISH);
        String langCode = LangEnum.getByCode(currentLocale.getLanguage()).getCode();

        //订单导入模板类型
        String countryCode = ContextUtils.getLoginAccount().getCountryCode();
        OmsImportTemplateConfig.CountryImportConfig countryImportConfig = omsImportTemplateConfig.getCountryImportConfig(countryCode);
        if (countryImportConfig == null) {
            countryImportConfig = omsImportTemplateConfig.getImportConfig().get("GH");
        }
        String templateFileName = countryImportConfig.getTemplate().get(langCode);
        response.setHeader("Content-disposition", "attachment;filename=" + URLUtil.encode(templateFileName, "utf-8"));

        String redisKey = RedisConstant.OMS_ORDER_ERROR_LIST_EXPORT_KEY + exportKey;
        // 导出错误的订单
        RBucket<List<WarehouseExcelImportDto>> bucket = redissionLock.getRedissonClient().getBucket(redisKey, new JsonJacksonCodec());
        if (!bucket.isExists()) {
            log.error("exportErrorOrderList.bucket.notExist.redisKey:{}", redisKey);
            throw new BussinessCodeException(INTERNAL_SERVER_ERROR);
        }
        List<WarehouseExcelImportDto> orderExcelDtoList = bucket.get();
        if (CollectionUtils.isEmpty(orderExcelDtoList)) {
            throw new BussinessCodeException(INTERNAL_SERVER_ERROR);
        }

        // 复制到导出 DTO。确保 WarehouseErrorExcelExportDto 中有 errorDesc 字段,
        List<WarehouseErrorExcelExportDto> exportDtos = orderExcelDtoList.stream()
                .map(dto -> {
                    WarehouseErrorExcelExportDto exportDto = BeanExUtil.copyProperties(dto, WarehouseErrorExcelExportDto.class);
                    // 组装错误描述:多个错误用分号拼起来
                    if (!CollectionUtils.isEmpty(dto.getErrorMessageList())) {
                        String desc = String.join(";", dto.getErrorMessageList());
                        exportDto.setErrorMessageList(desc);
                    }
                    return exportDto;
                })
                .collect(Collectors.toList());

        // 模板存放位置
        Path templateFileDir = Paths.get(templatePath).resolve(templateFileName);

        // 注意:如果模板已更新(新增了“错误描述”列),必须删除本地旧模板或强制覆盖,否则不会生效。
        // 这里简单处理:每次导出都重新下载模板。如果导出频繁,建议改用模板版本号或判断最后修改时间。
        try {
            Files.deleteIfExists(templateFileDir);
        } catch (IOException e) {
            log.warn("delete.old.template.failed, path:{}", templateFileDir, e);
        }

        try (OSSObject ossObject = FileSystemClient.getPrivateClient().getObject(templateFileName);
             InputStream inputStream = ossObject.getObjectContent()) {
            // 确保目录存在
            Files.createDirectories(templateFileDir.getParent());
            // 复制文件(自动处理缓冲区)
            Files.copy(inputStream, templateFileDir, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            log.error("download.templateFile.error", e);
            throw new BussinessCodeException(INTERNAL_SERVER_ERROR);
        }

        // 错误订单写入模板 excel
        try (InputStream templateStream = Files.newInputStream(templateFileDir)) {

            Workbook workbook = WorkbookFactory.create(templateStream);
            Sheet sheet = workbook.getSheetAt(0);

            int insertCol = 0; // 在第 0 列(A列)前插入

            // 1. 先处理合并区域:把所有起始列 >= 0 的合并区域整体右移 1 列
            List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
            // 先记录再清除再重建,避免遍历时修改报错
            List<CellRangeAddress> newMerged = new ArrayList<>(mergedRegions.size());
            for (CellRangeAddress region : mergedRegions) {
                int firstCol = region.getFirstColumn();
                int lastCol  = region.getLastColumn();
                if (firstCol >= insertCol) {
                    // 右移一列
                    newMerged.add(new CellRangeAddress(
                            region.getFirstRow(), region.getLastRow(),
                            firstCol + 1, lastCol + 1));
                } else {
                    newMerged.add(region); // 不涉及,保持原样
                }
            }
            // 清除旧的合并
            for (int i = 0; i < mergedRegions.size(); i++) {
                sheet.removeMergedRegion(0); // 每次移除第 0 个,下标自动前移
            }
            // 加回新的
            newMerged.forEach(sheet::addMergedRegion);

            // 2. 两行表头都右移一列
            for (int rowIdx = 0; rowIdx <= 1; rowIdx++) {
                Row row = sheet.getRow(rowIdx);
                if (row == null) {
                    row = sheet.createRow(rowIdx);
                }
                // 从最后一列往前移,避免覆盖
                int lastCol = row.getLastCellNum(); // 注意:getLastCellNum 是下一个空位
                for (int i = lastCol; i >= 0; i--) {
                    Cell old = row.getCell(i);
                    if (old != null) {
                        Cell newCell = row.createCell(i + 1);
                        newCell.setCellValue(old.getStringCellValue());
                        newCell.setCellStyle(old.getCellStyle());
                        // 清空原位置
                        row.removeCell(old);
                    }
                }
            }

            // 3. 写入 A 列表头(两行)
            Row headRow0 = sheet.getRow(0);
            Row headRow1 = sheet.getRow(1);
            if (headRow0 == null) headRow0 = sheet.createRow(0);
            if (headRow1 == null) headRow1 = sheet.createRow(1);

            Cell a0 = headRow0.createCell(0);
            Cell a1 = headRow1.createCell(0);

            String headText = MessageUtil.getMessageWithLangAndParam(MessageConstant.INCORRECT_DESCRIPTION, langCode);
            a0.setCellValue(headText);
            a1.setCellValue(""); // 第二行留空,或与第一行合并

            // 让 A 列的两行合并成一个表头单元格
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 0));

            // 4. 写回字节流,交给 EasyExcel
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            workbook.write(bos);
            workbook.close();

            try (ByteArrayInputStream modifiedTemplate = new ByteArrayInputStream(bos.toByteArray())) {
                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                        .withTemplate(modifiedTemplate)
                        .build();
                WriteSheet writeSheet = EasyExcel.writerSheet().sheetNo(0).build();
                excelWriter.write(exportDtos, writeSheet);
                excelWriter.finish();
            }
        } catch (Exception e) {
            log.error("exportExcel.error", e);
            throw new BussinessCodeException(INTERNAL_SERVER_ERROR);
        }
    }

  

posted @ 2026-10-15 17:41  客至在水一方  阅读(2)  评论(0)    收藏  举报