word poi tl 导出

public void exportWord(DealAfterReport dealAfterReport,HttpServletResponse response) throws Exception {
// 1. 准备所有数据(普通文本 + 静态表格 + 循环列表)
Map<String, Object> dataMap = new HashMap<>();
DealBase dealBase = new DealBase();
dealBase.setDealName("dealName*************");
dataMap.put("dealBase", dealBase);

// 【普通文本】
dataMap.put("tittle", "年度财务报告");

// 【静态表格】(对应模板中的 {{tableTest}})
RowRenderData row0 = Rows.of("姓名", "学历").textColor("FFFFFF")
.bgColor("4472C4").center().create();
RowRenderData row1 = Rows.create("李四", "博士");
dataMap.put("tableTest", Tables.create(row0, row1));

// 【循环表格数据 1】(对应模板中的 {{#aaa}})
List<Map<String, Object>> risks = new ArrayList<>();
risks.add(Map.of("name", "技术风险", "level", "高"));
risks.add(Map.of("name", "市场风险", "level", "中"));
dataMap.put("aaa", risks);

// 【循环表格数据 2】(假设模板中还有一个 {{#bbb}})
List<Map<String, Object>> profits = new ArrayList<>();
profits.add(Map.of("month", "1月", "amount", "100万"));
dataMap.put("bbb", profits);

// 2. 明确指定模板中需要动态循环的标签名
List<String> loopTags = Arrays.asList("aaa", "bbb");

// 3. 调用通用工具方法
exportWordUtils(dataMap, response, "季度投后管理报告模板.docx", "年度财务报告121.docx", loopTags);
}

/**
* 通用 Word 导出工具方法
* @param dataMap 渲染数据集合
* @param response HTTP响应对象
* @param templateName 模板文件名 (如: 季度投后管理报告模板.docx)
* @param outFileName 导出的目标文件名 (如: 年度财务报告.docx)
* @param loopTags 需要绑定 HackLoopTableRenderPolicy 的循环标签列表
*/
public void exportWordUtils(Map<String, Object> dataMap, HttpServletResponse response,
String templateName, String outFileName,
List<String> loopTags) throws Exception {

// 1. 设置 HTTP 响应头 (兼容各种浏览器的中文文件名下载)
String encodedFileName = URLEncoder.encode(outFileName, StandardCharsets.UTF_8.name())
.replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);

// 2. 读取模板文件 (约定模板统一放在 resources/template/ 目录下)
String templatePath = "/template/" + templateName;
try (InputStream templateIs = this.getClass().getResourceAsStream(templatePath)) {
if (templateIs == null) {
throw new RuntimeException("模板文件未找到,请检查路径:" + templatePath);
}

// 3. 动态构建 Configure 配置
ConfigureBuilder builder = Configure.builder();
HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();

// 遍历传入的标签列表,动态绑定策略
if (loopTags != null && !loopTags.isEmpty()) {
for (String tag : loopTags) {
builder.bind(tag, policy);
}
}
Configure config = builder.build();

// 4. 编译、渲染并写出
XWPFTemplate template = XWPFTemplate.compile(templateIs, config).render(dataMap);
template.write(response.getOutputStream());
template.close();
}
}

vue前台调用
handleExport(row) {
var fileName = this.reportQuarterFormat(row) + '投后管理报告'
const baseURL = process.env.VUE_APP_BASE_API || ''
const params = {
id: row.id
}
axios({
method: 'get',
url: baseURL + '/afterReport/dealAfterReport/exportWord',
params: params, // 2. 通过 params 传递参数
responseType: 'blob'
})
.then((response) => {
// 【关键修改3】Blob type 必须与后端 Content-Type 严格一致
const blob = new Blob([response.data], {
type: 'text/html;charset=UTF-8'
})

const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)

// 文件名保持 .doc,Word 会根据内容自动识别为 HTML 格式的 Word 文档
link.download = fileName + '.doc'

document.body.appendChild(link)
link.click()

document.body.removeChild(link)
window.URL.revokeObjectURL(link.href)
})
.catch((error) => {
console.error('导出失败:', error)
this.$message.error('导出失败')
})
},


image

模板中值得特殊说明的 一点是    {{#aaa}} 代表表格的开始    不需要表格结束标识,  [name] 是aaa列表中的属性, 用 [] 不是{{}}

image

 

 

posted @ 2026-07-15 15:50  翘中之楚  阅读(8)  评论(0)    收藏  举报