【Java导出word】使用poi-tl轻松实现Java导出数据到Word文档

文章目录


一、前言

Word文档动态生成长期面临三大痛点:

  • 传统POI的API操作繁琐(需手动创建Run/Paragraph等元素)、
  • 复杂格式难以保持一致性、
  • 大文件导出易引发内存溢出。

poi-tl作为基于Apache POI的模板引擎,通过声明式模板设计实现了代码与样式的解耦,其轻量级内核(仅1.2MB)相比原生POI减少80%的代码量,在10万行数据量场景下内存消耗降低65%。

本文基于实际报表需求场景,详解如何通过模板语法与数据绑定机制实现高效文档输出,助力你摆脱低效的文档构造模式,掌握导出数据到word到技术能力。


二、环境准备

  1. JDK版本要求(1.8+)
  2. Maven依赖配置
xml 复制代码
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.12.1</version>
</dependency>

三、使用流程

1、 标准DOCX模板创建

先创建好一个word文档,内容是自己的报表模板, 直接贴到word文档里就好。

在指定位置,加上占位符标签,后续由poi-tl进行模板内容替换。

模板内容:

复制代码
标题:{{year}}年 {{month}}月------统计报表

条件标签
{{?hasData}}
这里是条件标签,标签值为true时,会展示这块内容
表格:
{{#table}}
{{/hasData}}

{{?withoutData}}
指定的时间范围内,查询不到数据.
{{/withoutData}}

2. 占位符语法详解

  • 文本变量:{{title}}
  • 表格变量:{{#table}}
  • 条件判断:{{?condition}}...{{/condition}}

四、实战代码示例

单测代码

java 复制代码
/**
 * @Author: suwg
 * @Date: 2025/3/19
 */
@RunWith(MockitoJUnitRunner.class)
public class CompArchiveAuditServiceTest {
    @Test
    @SneakyThrows
    public void testWord() {
        String mainDocPath = "/Users/suweibo/Documents/模板.docx";

        // 构建合并文档集(支持批量)
        try (InputStream inputStream = new FileInputStream(mainDocPath)) {

            Map<String, Object> data = new HashMap<>();
            data.put("year", "2025");
            data.put("month", "03");
            data.put("hasData", true);   // true 则会展示标签包裹起来的内容
            data.put("withoutData", false); // false 则不会展示标签包裹起来的内容


            // 表格造数
            List<ArchivesDto> dtoList = new ArrayList<>();
            ArchivesDto dto = new ArchivesDto();
            dto.setAlarmType(4);
            dto.setWorkOrderCount(10);
            dto.setWordHandleResult("3条车辆续航低客户自行充电,7条无用车人联系方式");
            dtoList.add(dto);

            //表格数据构造
            RowRenderData headerRow = Rows.of("告警名称", "告警数量", "原因排查和处理方式").textBold().create();

            List<RowRenderData> tableData = new ArrayList<>();
            //从业务Dto对象读取对应字段的值,转成String
            for (ArchivesDto archivesDto : dtoList) {
                RowRenderData row = Rows.of(WarningContentEnum.getMsgByType(archivesDto.getAlarmType()),
                        archivesDto.getWorkOrderCount().toString(), archivesDto.getWordHandleResult()).create();
                tableData.add(row);
            }


            Tables.TableBuilder builder = Tables.of(headerRow);
            tableData.forEach(builder::addRow);

            TableRenderData table = builder
                    .create();
            data.put("table", table);


            // 执行合并(带异常重试机制)
            XWPFTemplate.compile(mainDocPath)
                    .render(data)
                    .writeToFile("数据替换后的文档.docx");
        }

    }
}

执行结果:

可以看到,生成的word文档里,对应的模板标识占位符号,已经被成功替换了,对应条件标签值为 false的情况,包裹的内容是不展示的。

总结

  1. 核心技术价值
  • 声明式模板设计:模板与Java代码解耦,样式控制完全由DOCX模板定义
  • 内存优化:10万级数据量场景内存消耗比原生POI降低65%
  • 开发效率:API封装度提升80%,无需手动操作Run/Paragraph等底层元素
  1. 模板语法体系
  • 基础变量:{{var}}实现纯文本替换
  • 区块控制:{{#table}}支持表格等结构化数据循环渲染
  • 逻辑分支:{{?condition}}...{{/condition}}实现动态内容显隐控制
  1. 数据绑定范式
  • 表格构造:通过TableBuilder逐行构建表头/数据行,支持样式链式调用(如.textBold())
  • 类型转换:DTO字段自动转String,结合枚举实现业务语义映射
  • 复合渲染:支持同时处理文本替换、表格生成、条件判断等多维度数据
  1. 生产级特性
  • 异常重试机制:模板合并过程内置容错处理
  • 批量处理:InputStream支持多文档合并操作
  • 格式保真:完全继承模板中的样式设定(字体/段落/表格样式等)
相关推荐
码智社10 小时前
Redis 哨兵模式详解:从原理到生产实践
java·redis
救救孩子把10 小时前
结构化输出为何“格式正确、答案错误”?JSON Schema 的能力边界
android·java·json·agent·agent服务
北冥you鱼11 小时前
Go 语言 GORM 使用 Preload:从关联查询到嵌套预加载的完整实践
开发语言·jvm·golang
silvamux_11 小时前
微头条爆款体平台适配实测:把交付要求变成可计算的指标
java·线性代数·算法·决策树·矩阵
论文复现现场11 小时前
DeepSeek V4.1 Flash 和 V4 Pro 有什么区别?API 价格、性能与迁移建议
java·服务器·人工智能·python·大模型api·deepseek·deepseek v4.1
dingzd9511 小时前
TikTok账号登录态失效的Cookie字段排查路径
开发语言·php·跨境电商·营销策略
曹牧11 小时前
C#:The operation has timed out
开发语言·c#
郭小李11 小时前
转发与重定向
java·服务器·数据库
你看我名字11 小时前
数眼智能 Search + Reader 实战:联网问答怎样避免“搜到了,却引用错了”
android·java·开发语言
小嘉丶学长11 小时前
Day13 · 列表与元组
linux·运维·服务器·开发语言·python