替换word中的excel
@PostMapping("/make/report/target/performance/first")
public AjaxResult makeTargetReportFirst(@RequestBody MakeReportDTO makeReportDTO) {Map<String, String> textReplaceMap = new HashMap<>();// 替换日期LocalDateTime nowData = LocalDateTime.now();DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");textReplaceMap.put("${nowDate}", nowData.format(dateFormatter));String templatePath = uploadPklExcelPath + "template1.docx";String directoryPath = fileUploadDir;try {if (!Files.exists(Paths.get(directoryPath))) {Files.createDirectories(Paths.get(directoryPath));}try (InputStream is = new FileInputStream(templatePath);XWPFDocument doc = new XWPFDocument(is)) {// 替换普通文本占位符(段落和表格内文本)replaceTextPlaceholders(doc, textReplaceMap);List<List<String>> excelData = makeReportDTO.getExcelData();if (excelData == null || excelData.isEmpty()) {return AjaxResult.error("excelData不能为空");}// 替换表格内容,按列替换,且新增行replaceTableDataByColumns(doc, excelData);// 生成唯一文件名String fileName = generateUniqueFileName();String outPath = directoryPath + fileName;try (OutputStream os = new FileOutputStream(outPath)) {doc.write(os);}return AjaxResult.success(outPath);}} catch (FileNotFoundException e) {return AjaxResult.error("文件未找到:" + e.getMessage());} catch (Exception e) {e.printStackTrace();return AjaxResult.error("报告生成失败:" + e.getMessage());}
}private void replaceTextPlaceholders(XWPFDocument doc, Map<String, String> replaceMap) {// 替换段落中的占位符doc.getParagraphs().forEach(paragraph -> {paragraph.getRuns().forEach(run -> {String text = run.getText(0);if (text != null) {for (Map.Entry<String, String> entry : replaceMap.entrySet()) {if (text.contains(entry.getKey())) {run.setText(text.replace(entry.getKey(), entry.getValue()), 0);}}}});});// 替换表格中的占位符doc.getTables().forEach(table -> {table.getRows().forEach(row -> {row.getTableCells().forEach(cell -> {cell.getParagraphs().forEach(paragraph -> {paragraph.getRuns().forEach(run -> {String text = run.getText(0);if (text != null) {for (Map.Entry<String, String> entry : replaceMap.entrySet()) {if (text.contains(entry.getKey())) {run.setText(text.replace(entry.getKey(), entry.getValue()), 0);}}}});});});});});}private void replaceTableDataByColumns(XWPFDocument doc, List<List<String>> excelData) {if (doc.getTables().isEmpty()) {throw new IllegalArgumentException("模板中没有表格");}XWPFTable table = doc.getTables().get(0);// 求最大行数int maxRowCount = excelData.stream().mapToInt(List::size).max().orElse(0);int templateRowCount = table.getNumberOfRows();// 不够行就新增for (int i = templateRowCount; i < maxRowCount; i++) {table.createRow();}for (int col = 0; col < excelData.size(); col++) {List<String> colData = excelData.get(col);for (int row = 0; row < maxRowCount; row++) {XWPFTableRow tableRow = table.getRow(row);// 设置固定高度为 5mm(约 284 Twips)tableRow.setHeight(284);tableRow.setHeightRule(TableRowHeightRule.EXACT);// 确保当前行有对应列单元格while (tableRow.getTableCells().size() <= col) {tableRow.createCell();}XWPFTableCell cell = tableRow.getCell(col);// 清空旧内容cell.removeParagraph(0);// 写入新文本并设置字体样式为小四宋体(12pt)XWPFParagraph paragraph = cell.addParagraph();XWPFRun run = paragraph.createRun();String text = row < colData.size() ? colData.get(row) : "";run.setText(text);run.setFontFamily("宋体");run.setFontSize(10); // 小四:12pt}}}private String generateUniqueFileName() {long timestamp = System.currentTimeMillis();int randomNum = new Random().nextInt(10000);return timestamp + "_" + randomNum + ".docx";}
{"excelData": [["水用量","水泥用量","水泥-种类","水泥-细度","水泥-28天抗压强度","矿粉用量","矿粉-细度","矿粉-28天活性指数","粉煤灰用量","粉煤灰-细度","粉煤灰-28天活性指数","砂用量","砂-细度","砂-石粉含量","石用量","石-含泥量","石-压碎指标值","减水剂用量","减水剂-含固量","减水剂-水泥净浆流动度","增效剂用量","坍落度","3天抗压强度","7天抗压强度","28天抗压强度"],["150","145","0","1.6","57.7","50","3.9","106","90","32.4","73","895","2.84","9.40","1010","0.92","0","10","11.5","190","1.43","205","22.5","31.8","47.6"]]
}