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 进行深度定制。

相关推荐
呼啦啦啦啦啦啦啦啦2 分钟前
【Java】HashMap的详细介绍
java·数据结构·哈希表
kakwooi19 分钟前
易乐播播放器---压力测试
java·jmeter·测试
泉城老铁20 分钟前
在高并发场景下,如何优化线程池参数配置
spring boot·后端·架构
泉城老铁20 分钟前
Spring Boot中实现多线程6种方式,提高架构性能
spring boot·后端·spring cloud
昵称为空C29 分钟前
SpringBoot 实现DataSource接口实现多租户数据源切换方案
后端·mybatis
sufu10651 小时前
说说内存泄漏的常见场景和排查方案?
java·开发语言·面试
羊锦磊1 小时前
[ CSS 前端 ] 网页内容的修饰
java·前端·css
hrrrrb1 小时前
【Java Web 快速入门】九、事务管理
java·spring boot·后端
AirMan2 小时前
深入解析 Spring Caffeine:揭秘 W-TinyLFU 缓存淘汰策略的高命中率秘密
后端