Java怎样实现将数据导出为Word文档

文章首发于我的博客:Java怎样实现将数据导出为Word文档 - Liu Zijian's Blog

我们在开发一些系统的时候,例如OA系统,经常能遇到将审批单数据导出为word和excel文档的需求,导出为excel是比较简单的,因为excel有单元格来供我们定位数据位置,但是word文档的格式不像表格那样可以轻松的定位,要想将数据导出为一些带有图片和表格的这种结构复杂的word文档该怎样实现呢。

poi-tl [1]是一款可以帮助我们实现这种功能的Java开源项目,它把POI和Freemarker相结合,可以基于我们绘制好的word文档模板来填充数据进去,然后生成新的word文档。poi-tl托管在GitHub:https://github.com/Sayi/poi-tl

例如,我们要生成一个差旅行程单,首先要绘制这样的一个word文档模板,用{{name}}代表姓名进行占位,姓名就是普通文字类型,以此类推。tripList作为渲染行程表格的数据源的名字,是ArrayList集合类型,放在表格的表头,用[from]表示tripList集合中每个元素的from属性的值,渲染到当前行的某一列上,以此类推。最后的三个签署对应的是领导的签名笔迹图片,图片类型要用变量名前多一个@的形式{{@****Pin}}来表示

如果表格中某一列是图片,则表示为[@变量]

image

模板绘制好以后,开始使用poi-tl工具生成word文档,首先新建maven项目,引入poi-tl的依赖和需要的其他依赖,然后将这个绘制好的word模板文件放在工程的根目录

```xml


    4.0.0

    org.example
    poi-tl
    1.0-SNAPSHOT

    
        8
        8
        UTF-8
    

    
        
            com.deepoove
            poi-tl
            1.12.2
        

        
            org.projectlombok
            lombok
            1.18.24
            provided
        
    


```

然后,新建一个Entity类: org.example.TravelApplyExportVO

```java
package org.example;

import com.deepoove.poi.data.PictureRenderData;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TravelApplyExportVO {
    private String no;
    private String name;
    private String dept;
    private String employeeNo;
    private String start;
    private String end;
    private String days;
    private String address;
    private String reason;
    /**
     * com.deepoove.poi.data.PictureRenderData 代表图片
     */
    private PictureRenderData applyPin;
    private PictureRenderData bossPin;
    private PictureRenderData leaderPin;

    private String date;

    /**
     * 用于渲染表格的集合
     */
    private List tripList = new ArrayList<>();

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Route {
        private String from;
        private String to;
        private String flight;
        private String depTime;
        private String arrTime;
        private String cabin;
    }
}
```

新建测试类: org.example.Main,用poi-tl组件基于刚刚绘制的word模板生成一个差旅行程单

```java
package org.example;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import lombok.SneakyThrows;


import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;

public class Main {

    @SneakyThrows
    public static void main(String[] args) {

        TravelApplyExportVO vo = new TravelApplyExportVO();
        vo.setNo("202500001");
        vo.setName("lzj");
        vo.setDept("技术部");
        vo.setEmployeeNo("00000001");
        vo.setStart("2025-01-01");
        vo.setEnd("2025-02-01");
        vo.setDays("30");
        vo.setAddress("中国香港");
        vo.setReason("系统维护");

        // 在项目根路径读取笔迹图片,并设置大小
        PictureRenderData data1 = Pictures.ofBytes(Files.readAllBytes(Paths.get("img2.png")))
                .size(120, 60)
                .create();

        PictureRenderData data2 = Pictures.ofBytes(Files.readAllBytes(Paths.get("img.png")))
                .size(120, 60)
                .create();

        PictureRenderData data3 = Pictures.ofBytes(Files.readAllBytes(Paths.get("img.png")))
                .size(120, 60)
                .create();

        vo.setApplyPin(data1 );
        vo.setBossPin( data2);
        vo.setLeaderPin( data3);

        vo.setDate("2025-01-10");

        // 行程List,最终渲染到文档的表格中
        vo.setTripList(new ArrayList() {
            {
                add(new TravelApplyExportVO.Route("BJX","ZQZ","ZH5643","2025-01-01 15:00","2025-01-01 16:00","E"));
                add(new TravelApplyExportVO.Route("ZQZ","CDE","JUH6532","2026-01-01 15:00","2025-12-01 16:00","A"));
                add(new TravelApplyExportVO.Route("BJX","ZQZ","KJU0954","2027-01-01 15:00","2025-05-01 16:00","Q"));
            }
        });

        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();

        // !!将tripList通过表格来渲染
        Configure config = Configure.builder()
                .bind("tripList", policy)
                .build();

        XWPFTemplate template = XWPFTemplate
                .compile("模板.docx", config)
                .render(vo);

        template.writeAndClose(Files.newOutputStream(Paths.get("output.docx")));
    }
}
```

然后领导签名笔记图片素材img.png,img2.png也需要放进工程根目录下

都完成后,执行main()方法测试,程序运行结束后,将在根路径生成文件output.docx,打开就是我们想要的效果了。

image

文章写到这已经是深夜了,最新在开发一个OA系统,需要Word导出的场景很多,由于之前没怎么接触过,于是熬夜攻关了一下并记录了下来,接下来希望项目能顺利交付吧~

参考


  1. https://deepoove.com/poi-tl/ ↩︎

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/6143.html

(0)
LomuLomu
上一篇 2025 年 1 月 13 日 上午6:11
下一篇 2025 年 1 月 13 日 上午6:47

相关推荐

  • 【深度学习】Java DL4J基于 LSTM 构建新能源预测模型

    🧑 博主简介:CSDN博客专家 ,历代文学网 (PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学 ”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理…

    未分类 2025 年 1 月 21 日
    56100
  • UML扩展用例的应用与实践

    在UML建模中,用例分析是描述业务实现或系统功能的重要手段。每个用例都代表一个完整的业务流程或功能模块。然而,在实际应用中,某些功能可能并非核心需求,而是作为可选补充存在。针对这种情况,UML提供了扩展用例机制来灵活处理这类场景。以银行业务为例,”存款”和”取款”是最基础的核心用例。在完成这些交易后,客户可以选择对服务进行评价,但这个环节并非强制要求。我们可…

    2025 年 5 月 12 日
    23900
  • 华为OD机试E卷 –羊、狼、农夫过河–24年OD统一考试(Java & JS & Python & C & C++)

    文章目录 题目描述 输入描述 输出描述 用例 题目解析 JS算法源码 Java算法源码 python算法源码 c算法源码 c++算法源码 题目描述 羊、狼、农夫都在岸边,当羊的数量小于狼的数量时,狼会攻击羊,农夫则会损失羊。农夫有一艘容量固定的船,能够承载固定数量的动物。要求求出不损失羊情况下将全部羊和狼运到对岸需要的最小次数。只计算农夫去对岸的次数,回程时…

    未分类 2025 年 1 月 19 日
    49700
  • Bolt.new 30秒做了一个网站,还能自动部署,难道要吊打 Cursor?

    大家好,我是汤师爷~ 这篇聊聊 Bolt.new 和 Cursor 的对比。 Bolt.new 是一款基于 SaaS 的 AI 编码平台。它由 LLM 驱动的智能体作为底层,并结合 WebContainers 技术,让用户可以直接在浏览器中进行编码和运行。其主要优势包括: 支持前后端同时开发; 项目文件夹结构可视化; 环境自托管,自动安装依赖(如 Vite、…

    2025 年 1 月 16 日
    54200
  • UML序列图中消息传递机制解析

    在UML序列图中,各交互对象通过特定形式的通信完成特定行为,这些通信以消息为载体并按时间顺序排列。消息本质上是生命线之间的信息传递,通常以水平或向下倾斜的箭头表示,箭头起始于发送方生命线,终止于接收方生命线。消息可携带参数,但需注意参数类型与取值必须符合接收方角色定义的操作规范。1. 同步通信及其反馈机制实线配合实心箭头代表同步消息。发送方发出此类消息后会暂…

    2025 年 5 月 11 日
    27900

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信