Spring Boot 中根据 Word 模板导出包含表格、图表等复杂格式的文档

在 Spring Boot 中根据 Word 模板导出包含表格、图表等复杂格式的文档,可通过以下方案实现。以下是综合多篇技术博客和最佳实践的完整指南:


一、技术选型与方案对比

方案 优点 缺点 适用场景
​poi-tl​ 直接操作 Word 模板,支持动态循环、合并单元格,开发效率高 需熟悉模板语法,图表需结合其他库生成 快速开发,模板复杂度中等
​Apache POI​ 灵活性强,支持底层操作文档结构 代码量大,模板处理复杂度高 高度定制化需求
​Freemarker/Thymeleaf​ 模板语法简单,适合文本替换 需 XML 转换,图表生成困难 纯文本或简单表格

​推荐方案​ ​:优先使用 ​​poi-tl​​(结合 JFreeChart 生成图表),兼顾开发效率和功能完整性。


二、poi-tl 实现步骤(含表格与图表)

1. 添加依赖

xml 复制代码
<!-- poi-tl 核心依赖 -->
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.12.2</version>
</dependency>
<!-- 图表生成依赖 -->
<dependency>
    <groupId>org.jfree</groupId>
    <artifactId>jfreechart</artifactId>
    <version>1.5.4</version>
</dependency>

2. 设计 Word 模板

  • ​表格模板​​:

    css 复制代码
    {{userList}} 姓名 | 性别 | 年龄
    ---|---|---
    [name] | [sex] | [age]
  • ​图表处理​​:

    使用 JFreeChart 生成图表图片,插入到 Word 指定位置(poi-tl 不支持直接生成图表)。

3. 代码实现

arduino 复制代码
// 配置渲染策略(合并单元格、循环渲染)
Configure config = Configure.builder()
    .useSpringEL()
    .bind("list1", new LoopRowTableRenderPolicy())  // 行循环
    .bind("tableList", new ReportDataPolicy())      // 自定义合并策略
    .build();

// 加载模板并渲染数据
XWPFTemplate template = XWPFTemplate.compile("template.docx", config)
    .render(dataMap);

// 输出到响应流(支持下载)
template.write(response.getOutputStream());

4. 自定义合并单元格策略

scala 复制代码
public class ReportDataPolicy extends DynamicTableRenderPolicy {
    @Override
    public void render(XWPFTable table, Object data) {
        // 解析数据并动态插入行
        List<BsReportData> list = JSON.parseArray(JSON.toJSONString(data), BsReportData.class);
        for (BsReportData item : list) {
            RowRenderData row = Rows.of(item.getField1(), item.getField2()).create();
            table.insertNewTableRow().render(row);
        }
    }
}

三、Apache POI 直接操作方案

1. 核心代码(表格生成)

scss 复制代码
XWPFDocument document = new XWPFDocument();
XWPFTable table = document.createTable(3, 3); // 3行3列
table.getRow(0).getCell(0).setText("标题");
// 动态填充数据
for (int i=0; i<dataList.size(); i++) {
    table.getRow(i+1).getCell(0).setText(dataList.get(i).getName());
}

2. 图表生成(需结合 JFreeChart)

ini 复制代码
// 生成柱状图
JFreeChart chart = ChartFactory.createBarChart(...);
// 转换为 BufferedImage
BufferedImage image = chart.createBufferedImage(400, 300);
// 插入 Word
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.addPicture(new ByteArrayInputStream(toByteArray(image)), XWPFDocument.PICTURE_TYPE_PNG, "chart.png", Units.toEMU(400), Units.toEMU(300));

四、模板设计最佳实践

  1. ​占位符规范​

    • 简单变量:{{fieldName}}
    • 循环列表:{{listName}}+ 表头占位符(如 [name]
  2. ​复杂格式处理​

    • 合并单元格:通过代码动态操作 XWPFTableRowXWPFTableCell
    • 样式继承:在 Word 模板中预定义样式,避免代码中硬编码格式
  3. ​图表兼容性​

    • 优先使用 SVG 格式(高分辨率)
    • 测试不同 Office 版本的显示效果

五、方案对比与选择建议

场景 推荐方案 理由
快速原型开发 poi-tl 模板直观,开发周期短
高定制化需求 Apache POI 完全控制文档结构和样式
纯文本/简单表格 Freemarker 模板编写简单,无需处理二进制流

六、常见问题解决

  1. ​图表显示异常​

    • 确保图片分辨率 ≥ 300dpi
    • 使用 XWPFRun.addPicture()时指定正确 MIME 类型
  2. ​模板变量不生效​

    • 检查占位符语法是否与代码中的键名一致
    • 使用 Configure.builder().useSpringEL()启用 SpEL 表达式支持
  3. ​大文件内存溢出​

    • 使用 SXSSFWorkbook替代 XSSFWorkbook
    • 分页写入数据,避免一次性加载全部内容

通过上述方案,可灵活实现包含动态表格、图表等复杂格式的 Word 导出功能。推荐优先采用 ​​poi-tl​​ 方案平衡开发效率与功能完整性,复杂场景可结合 Apache POI 进行深度定制。

相关推荐
小荷才露尖尖角,早有蜻蜓立上头23 分钟前
过滤器的4种创建方式
java
大圣编蚕33 分钟前
Java ByteArrayInputStream 详解:从入门到实战
java·开发语言·算法
程序员阿明1 小时前
idea把插件啥的不默认放在C盘
java·ide·intellij-idea
linweidong1 小时前
中科闻歌Java面试题及参考答案
java·python·大模型·提示词·ai agent·mcp·rag原理
OpenAnolis小助手2 小时前
一句话看透 JVM,SysOM 诊断 Skill 新增 Java 应用诊断能力
java·开发语言·jvm·阿里云·操作系统控制台·sysom
ForteScarlet2 小时前
Kotlin 2.4.20 现已发布,新特性多不多?
android·java·开发语言·开源·kotlin·jetbrains
萧瑟余晖2 小时前
Java深入解析篇六十二之安全机制详解
java·开发语言
小刘在重生~2 小时前
Java 常用类|包装类 装箱拆箱、Integer 缓存面试题
java·python·缓存
Orange_sparkle2 小时前
Pi Agent vs LangGraph:从人机交互、企业 RAG 到持久化工作流的完整选型指南
java·网络·人机交互
IT_陈寒3 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端