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/6309.html

(0)
LomuLomu
上一篇 2025 年 1 月 14 日 上午6:16
下一篇 2025 年 1 月 14 日 上午7:18

相关推荐

  • Java Dubbo 面试题

    谈谈你理解的Dubbo? Dubbo是一个高性能的Java RPC框架,它提供了服务的注册、发现、调用以及监控等功能,使得开发者可以方便地构建分布式系统和服务化架构。 服务治理:Dubbo提供了一套服务治理的解决方案,包括服务的注册、发现、负载均衡、容错和监控等。 高性能:Dubbo支持多种协议,如Dubbo协议、RMI协议、HTTP协议等,其中Dubbo协…

    未分类 2025 年 1 月 15 日
    74200
  • Claude Pro续费充值教程:国内用户如何继续使用Claude

    Claude Pro续费充值教程,适合国内用户处理Claude续费、Claude代充和国内充值Claude需求。

    未分类 2026 年 6 月 4 日
    5400
  • 基于Redis有序集合实现滑动窗口限流

    滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间段内的请求次数。通过动态地滑动窗口,可以动态调整限流的速率,以应对不同的流量变化。 整个限流可以概括为两个主要步骤: 统计窗口内的请求数量 应用限流规则 Redis有序集合每个value有一个score(分数),基于score我们可以定义一个时间窗口,然后每次…

    2024 年 12 月 31 日
    59000
  • ChatGPT Plus开通会员充值完整流程操作指南

    ChatGPT Plus 对写作、办公和学习都很有用,但国内开通时容易遇到海外支付准备成本。相比换共享账号,直接给自己的账号充值更适合长期使用。 以下步骤保留完整入口、Session 链接和确认按钮名称。

    未分类 2026 年 6 月 8 日
    4800
  • Claude Pro支付宝代充亲测可用

    Claude Pro支付宝代充亲测可用,适合需要稳定使用 Claude 的国内用户,重点说明支付宝、账号核对和Pro 权限和使用限制变化。

    未分类 2026 年 5 月 20 日
    6600

发表回复

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

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

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

关注微信