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

Apache POI导出Excel:如何将金额与对应日期列关联

问题:Excel导出时金额与日期列无法正确关联

我有一个接收动态数据并保存到Excel文件的方法,列名是用户输入的日期,能正确获取这些日期,但导出的金额无法对应到正确的日期列。当前导出效果、期望效果及原代码如下,尝试用Map实现关联但未成功,请求解决。

原代码

private void saveExcel(List<ExplosureDto> list, List<String> columns, HttpServletResponse response) throws IOException {

    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet("Reports");
    XSSFRow row = sheet.createRow(0);

    List<Object> namesForRowZero = new ArrayList<>(columns);
    // Map<XSSFCell, Integer> namesForRowZero1 = new HashMap<>();
    for (int i = 0; i < namesForRowZero.size(); i++) {
        Cell cell = row.createCell(i);
        cell.setCellValue(String.valueOf(namesForRowZero.get(i)));
        cell.setCellStyle(excelStylesDtoService.greenColor(workbook));

        namesForRowZero1.put(sheet.getRow(0).getCell(i), i);
    }

    int second = sheet.getLastRowNum() + 1;

    for (ExplosureDto dto : list) {
        for (ChildExplosure childExplosure : dto.getChildExplosures()) {

            row = sheet.createRow(second);
            Cell cell1 = row.createCell(second);
            BigDecimal amount = childExplosure.getAmount();
            sheet.setColumnWidth(second, 20 * 256);
            cell1.setCellValue(amount.doubleValue());
            cell1.setCellStyle(excelStylesDtoService.styleBorder(workbook));
            second++;
        }
    }
    String report = "C:/download/Report.xlsx";
    FileOutputStream outputStream = new FileOutputStream(report);
    workbook.write(outputStream);
    workbook.close();

    outputStream.flush();
    outputStream.close();
}

当前错误导出效果

2022-01  |     2022-02    |   2022-03    |   2022-04    |   2022-05   |
------------+----------------+--------------+--------------+-------------+
            |   334008,0972  |              |              |             |
            |                |  334008,0972 |              |             |
            |                |              |  334008,0972 |             |
            |                |              |              | 334008,0972 |
            |                |              |              |             |  334008,0972

期望导出效果

2022-01  |     2022-02    |   2022-03    |   2022-04    |   2022-05   |
------------+----------------+--------------+--------------+-------------+
            |                | 334008,0972  | 334008,0972  | 334008,0972 |
            |                |  334008,0972 | 334008,0972  |             |
334008,0972 | 334008,0972    | 334008,0972  |  334008,0972 |             |
            | 334008,0972    |              |              | 334008,0972 |
            |                |              |              |             |  

解决方案

核心问题是原代码错误地将行号作为列索引创建单元格,导致金额无法匹配日期列。正确做法是建立「日期字符串→列索引」的映射,再根据数据中的日期找到对应列填充金额。

修正后的代码

private void saveExcel(List<ExplosureDto> list, List<String> columns, HttpServletResponse response) throws IOException {

    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet("Reports");
    XSSFRow headerRow = sheet.createRow(0);

    // 建立日期到列索引的映射(核心修正点)
    Map<String, Integer> dateColumnMap = new HashMap<>();
    for (int i = 0; i < columns.size(); i++) {
        String dateStr = columns.get(i);
        Cell cell = headerRow.createCell(i);
        cell.setCellValue(dateStr);
        cell.setCellStyle(excelStylesDtoService.greenColor(workbook));
        dateColumnMap.put(dateStr, i);
        // 统一设置列宽,避免重复操作
        sheet.setColumnWidth(i, 20 * 256);
    }

    // 处理数据行:每个ExplosureDto对应一行
    int dataRowNum = 1;
    for (ExplosureDto dto : list) {
        XSSFRow dataRow = sheet.createRow(dataRowNum);
        for (ChildExplosure childExplosure : dto.getChildExplosures()) {
            // 获取当前子项的日期,假设ChildExplosure有getDate()方法返回日期字符串
            String childDate = childExplosure.getDate();
            Integer colIndex = dateColumnMap.get(childDate);
            
            // 仅当日期存在于表头时填充金额
            if (colIndex != null) {
                Cell amountCell = dataRow.createCell(colIndex);
                BigDecimal amount = childExplosure.getAmount();
                amountCell.setCellValue(amount.doubleValue());
                amountCell.setCellStyle(excelStylesDtoService.styleBorder(workbook));
            }
        }
        dataRowNum++;
    }

    String report = "C:/download/Report.xlsx";
    try (FileOutputStream outputStream = new FileOutputStream(report)) {
        workbook.write(outputStream);
    } finally {
        workbook.close();
    }
}

关键修正说明

  1. 映射关系替换:将原有的Cell→Integer Map改为String→Integer Map,直接通过日期字符串定位列索引,这是关联日期与金额的核心。
  2. 数据遍历逻辑调整:每个ExplosureDto对应一行数据,该行下的所有ChildExplosure根据自身日期找到对应列填充金额,符合期望的多行多列布局。
  3. 移除错误的列索引逻辑:删除原代码中row.createCell(second)的错误写法,改为使用映射得到的正确列索引。
  4. 优化列宽设置:在表头循环中统一设置列宽,避免重复操作。

注意事项

确保ChildExplosure的日期字符串格式与表头的日期格式完全一致(例如都是yyyy-MM),否则映射会无法匹配列索引。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 21:20:37