You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java生成多份Excel发送优化:如何实现流复用并移出循环关闭?

优化Excel写入逻辑:流复用与资源管理改进

我来帮你梳理下这段代码的优化方向,主要围绕复用通用模板、简化资源管理和移出循环内重复操作这几个点来做,既能实现你想要的资源复用,也能让代码更简洁易维护:

核心优化思路

  • 抽离表头模板:所有Excel的表头完全一致,没必要每次循环都重复创建。预先生成带表头的Workbook模板,每次循环直接复制模板填充数据,减少冗余操作。
  • 自动资源管理:用Java 7+的try-with-resources替代手动调用IOUtils.closeQuietly,自动关闭流和Workbook资源,既可靠又省去手动关闭的繁琐。
  • 集中关闭资源:把模板Workbook的关闭操作移到循环外,只执行一次;循环内的临时Workbook在各自的作用域内关闭,避免资源泄漏。

优化后的代码实现

第一步:创建通用表头模板方法

先写一个只执行一次的方法,生成带表头的Workbook模板:

// 生成带表头的Excel模板,仅初始化一次
private XSSFWorkbook createLeaveListTemplate() {
    XSSFWorkbook templateWb = new XSSFWorkbook();
    Sheet sheet = templateWb.createSheet("人員離調不須覆核清單");
    
    // 批量创建表头,比逐个写更简洁
    String[] headerTitles = {
        "離調職", "資料日期", "員編", "應用系統代號",
        "使用者員編", "登入帳號", "系統群組代號", "最近登入日期",
        "匯入日期", "註記"
    };
    Row headerRow = sheet.createRow(0);
    for (int i = 0; i < headerTitles.length; i++) {
        headerRow.createCell(i).setCellValue(headerTitles[i]);
    }
    return templateWb;
}

第二步:优化循环逻辑

把资源创建、关闭逻辑重构,移出循环内的重复操作:

// 预先初始化模板,只执行一次
XSSFWorkbook templateWorkbook = createLeaveListTemplate();

try {
    for (String key : manMappingSys.keySet()) {
        // 复制模板Workbook,直接复用表头结构
        XSSFWorkbook currentWb = new XSSFWorkbook(templateWorkbook);
        Sheet sheet = currentWb.getSheetAt(0);
        int rowNum = 1; // 表头已占第0行,从第1行开始填充数据

        // 填充数据逻辑(和原代码一致,仅调整起始行号)
        List<String> sysList = manMappingSys.get(key);
        for (String sysId : sysList) {
            List<LeaveList> leaveList = sysMappingLeave.get(sysId);
            for (LeaveList leave : leaveList) {
                Row tempRow = sheet.createRow(rowNum);
                tempRow.createCell(0).setCellValue(leave.getChangeLeave());
                tempRow.createCell(1).setCellValue(leave.getDataDate().toString());
                tempRow.createCell(2).setCellValue(leave.getUserId());
                tempRow.createCell(3).setCellValue(leave.getSysNoId().getSc02ApType());
                tempRow.createCell(4).setCellValue(leave.getSysNoId().getUsrId());
                tempRow.createCell(5).setCellValue(leave.getSysNoId().getActNo());
                tempRow.createCell(6).setCellValue(leave.getSysNoId().getRgroup());
                tempRow.createCell(7).setCellValue(leave.getSysNoId().getLastDate().toString());
                // 提示:原代码中"匯入日期"和"註記"列未赋值,可根据业务需求补充
                rowNum++;
            }
        }

        // 用try-with-resources自动管理输出流,无需手动关闭
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            currentWb.write(outputStream);
            BufferedInputStream inputStream = new BufferedInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
            InputStreamResource excelResource = new InputStreamResource(inputStream, "人員離調不須覆核清單.xlsx");
            InputStreamResource[] attachments = {excelResource};

            // 发送邮件逻辑
            SysEmployee manager = employeeMapper.getEmployeeByCn(key);
            String[] toMails = {manager.getMail()};
            mailService.sendMail(
                SCHEDULE_LEAVE_OR_TRASFER_NOTICE_NOT_TEMPLATE,
                new HashMap(),
                Locale.getDefault(),
                toMails,
                attachments
            );
        } finally {
            // 关闭当前循环的临时Workbook
            IOUtils.closeQuietly(currentWb);
        }
    }
} finally {
    // 循环结束后关闭模板Workbook,仅执行一次
    IOUtils.closeQuietly(templateWorkbook);
}

优化细节解释

  1. 模板复用的优势:模板只创建一次,每次循环通过复制模板生成新的Workbook,避免了重复创建表头的冗余操作,尤其是当循环次数较多时,能明显提升性能。
  2. 资源管理改进:
    • 模板Workbook的关闭操作移到最外层的finally块,只执行一次,完全符合你“将流关闭操作移出循环”的需求。
    • 循环内的输出流通过try-with-resources自动关闭,不需要手动调用IOUtils.closeQuietly,代码更简洁且资源更安全。
  3. 代码可读性提升:把表头创建逻辑抽成独立方法,循环体只关注数据填充和邮件发送,结构更清晰,后续维护或修改表头也更方便。

内容的提问来源于stack exchange,提问作者user7189675

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:44:19