Skip to content

模板填充出现填充错误 #295

@shrayver

Description

@shrayver

Image
Image
Image

触发场景描述
利用模板填充,先将数据垂直填充,其中有一个字段是列表,将其输出问一个中间excel,然后利用中间的excel作为模板去填充具体的list,发现第一列会不会被填充掉,先用垂直填充将{tmPsnInfoList.tag}替换为{dataRecord_xxxx.data},然后通过中间的excel作为输入模板,填充{tmPsnInfoList.tag},发现第一列的数据为{dataRecord_xxxx.data}而不是列表的具体值

触发Bug的代码
public void doExportMonthReport(TmMonthReportVO tmMonthReportVO, HttpServletResponse response, HttpServletRequest request) {
// 1. 从类路径读取模板文件
String templateFileName = "template/月报模板.xlsx";
InputStream templateInputStream = null;
File firstOutputFile = null;
File finalOutputFile = null;
ExcelWriter excelWriter = null;

try {
    // 获取模板文件流
    templateInputStream = this.getClass().getClassLoader().getResourceAsStream(templateFileName);
    if (templateInputStream == null) {
        throw new RuntimeException("模板文件不存在: " + templateFileName);
    }

    // 2. 创建临时中间文件
    firstOutputFile = File.createTempFile("render_step1_", ".xlsx");
    String firstOutputFilePath = firstOutputFile.getAbsolutePath();

    // 第一步填充
    assembleAttendanceData(tmMonthReportVO);

    // 3. 第一次模板填充
    try{
        ExcelWriter firstExcelWriter = EasyExcel.write(firstOutputFilePath)
                .withTemplate(templateInputStream)
                .build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        Map<String, Object> renderMap = new HashMap<>();
        renderMap.put("year", tmMonthReportVO.getYear());
        renderMap.put("month", tmMonthReportVO.getMonth());

        FillConfig hfillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
        FillConfig vfillConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).build();

        firstExcelWriter.fill(new FillWrapper("dayMapping", tmMonthReportVO.getDayMapping()), hfillConfig, writeSheet);
        firstExcelWriter.fill(new FillWrapper("tmPsnInfoList", tmMonthReportVO.getTmPsnInfoList()), vfillConfig, writeSheet);
        firstExcelWriter.fill(renderMap, writeSheet);
        firstExcelWriter.finish();
    } catch (RuntimeException e) {
        throw new RuntimeException(e);
    }

    // 4. 创建最终输出临时文件
    finalOutputFile = File.createTempFile("render_final_", ".xlsx");
    String finalOutputFilePath = finalOutputFile.getAbsolutePath();


    if (!firstOutputFile.exists() || firstOutputFile.length() == 0) {
        throw new RuntimeException("第一次填充生成的文件无效");
    }

    // 5. 第二次模板填充
    try  {
        ExcelWriter finalExcelWriter = EasyExcel.write(finalOutputFilePath)
                .withTemplate(firstOutputFile)
                .build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        Map<String, Object> otherMap = new HashMap<>();

        for (Map<String, Object> map : tmMonthReportVO.getTmPsnInfoList()) {
            String pkPsndoc = (String) map.getOrDefault("pkPsndoc", "");
            List<Map<String, Object>> dataRecords = (List<Map<String, Object>>) map.get("dataRecord");

            if (dataRecords != null && !dataRecords.isEmpty()) {
                // 在第一次填充时占位符已经变为 "dataRecord_xxx.data",第二次填充时可以直接填充
                otherMap.put("dataRecord_" + pkPsndoc + ".data", dataRecords.get(0).getOrDefault("data", ""));

                // 正确填充第二次数据,填充到占位符 "dataRecord_xxx" 对应的地方
                FillConfig fillConfigHorizontal = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
                finalExcelWriter.fill(new FillWrapper("dataRecord_" + pkPsndoc, dataRecords), fillConfigHorizontal, writeSheet);
            }
        }
        finalExcelWriter.finish();
    } catch (RuntimeException e) {
        throw new RuntimeException(e);
    }

    // 6. 设置响应头,输出文件流
    response.setContentType("application/octet-stream");
    String fileName = URLEncoder.encode("月度考勤报表.xlsx", "UTF-8");
    response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";filename*=UTF-8''" + fileName);

    try (InputStream inputStream = new FileInputStream(finalOutputFile);
         OutputStream outputStream = response.getOutputStream()) {
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.flush();
    }

} catch (Exception e) {
    throw new RuntimeException("导出月报失败", e);
} finally {
    // 7. 清理临时文件
    try {
        if (templateInputStream != null) {
            templateInputStream.close();
        }
        if (firstOutputFile != null && firstOutputFile.exists()) {
            firstOutputFile.delete();
        }
        if (finalOutputFile != null && finalOutputFile.exists()) {
            finalOutputFile.delete();
        }
    } catch (IOException e) {
        // 清理失败不影响主流程
        e.printStackTrace();
    }
}

}

private void assembleAttendanceData(TmMonthReportVO tmMonthReportVO) {
List<Map<String, List<Map<String, Map<String, String>>>>> tmPsnAttendanceList = tmMonthReportVO.getTmPsnAttendanceList();
for (Map<String, Object> map : tmMonthReportVO.getTmPsnInfoList()) {
String pkPsndoc = (String)map.getOrDefault("pkPsndoc","");
Optional<Map<String, List<Map<String, Map<String, String>>>>> attendanceData = tmPsnAttendanceList.stream().filter(map1 -> map1!=null && map1.containsKey(pkPsndoc)).findFirst();
List<Map<String,Object>> data= new LinkedList<>();
if (attendanceData.isPresent()){
Map<String, List<Map<String, Map<String, String>>>> record = attendanceData.get();
for (Map.Entry<String, List<Map<String, Map<String, String>>>> entry : record.entrySet()) {
List<Map<String, Map<String, String>>> attendenceRecord = entry.getValue();
for (Map<String, Map<String, String>> mapMap : attendenceRecord) {
for (Map.Entry<String, Map<String, String>> mapEntry : mapMap.entrySet()) {
Map<String, String> acutalRecord = mapEntry.getValue();
Map<String, Object> dataRecord = new HashMap<>();
String minTime = acutalRecord.get("minTime");
String maxTime = acutalRecord.get("maxTime");
dataRecord.put("data", minTime + "\n" + maxTime);
data.add(dataRecord);
}
}
}
}else {
int size = tmMonthReportVO.getDayMapping().size();
for (int i = 0; i < size; i++) {
Map<String, Object> dataRecord = new HashMap<>();
dataRecord.put("data", "");
data.add(dataRecord);
}
}
map.put("dataRecord", data);
map.put("tag", "{dataRecord_"+pkPsndoc+".data}");
}

}

Image
Image
Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is neededquestionFurther information is requested

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions