文章首发于我的博客: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}}来表示

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

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

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId>
<artifactId>poi-tl</artifactId>
<version>1.0-SNAPSHOT</version> <properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.2</version>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies> </project>

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

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<Route> 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模板生成一个差旅行程单

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<TravelApplyExportVO.Route>() {
{
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,打开就是我们想要的效果了。

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

参考


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

Java怎样实现将数据导出为Word文档的更多相关文章

  1. javadoc导出成word文档

    刚刚上次弄完了一个坑爹的任务,这次我领导又给我一个让人脑瓜子疼的任务了. 基本上客户他在验收我们系统的时候,都会要求我们编写相关的文档,这次也不例外. 只是这次的客户要求我们给出接口文档.不仅是要整个 ...

  2. PowerDesigner将PDM导出生成WORD文档

    PowerDesigner将PDM导出生成WORD文档 环境 PowerDesigner15 1.点击Report Temlates 制作模板 2.如果没有模板,单击New图标创建.有直接双击进入. ...

  3. 将HTML导出生成word文档

    前言: 项目开发中遇到了需要将HTML页面的内容导出为一个word文档,所以有了这边随笔. 当然,项目开发又时间有点紧迫,第一时间想到的是用插件,所以百度了下.下面就介绍两个导出word文档的方法. ...

  4. (转)WEB页面导出为Word文档后分页&横向打印的方法

    <html>    <HEAD>        <title>WEB页面导出为Word文档后分页&横向打印的方法 </title>    < ...

  5. 网页导出成word文档的默认视图方式问题

    网页导出成word文档的默认视图方式问题 一般保存后的word文档默认是“Web版式视图”打开,这样会给客户的感觉不是真正的word文档,必须实现打开就是“页面视图” 1. 修改<html> ...

  6. 可以把思维导图导出为word文档方便其他人查看吗?

    MindManager除了强大的大纲视图编辑功能外,还拥有多种导出格式,方便大家迅速导出文件,在团队中分享自己的观点,提高团队的工作效率,本次小编使用的思维导图软件版本是MindManager 202 ...

  7. Java中用Apache POI生成excel和word文档

    概述: 近期在做项目的过程中遇到了excel的数据导出和word的图文表报告的导出功能.最后决定用Apache POI来完毕该项功能.本文就项目实现过程中的一些思路与代码与大家共享.同一时候.也作为自 ...

  8. 如何在PowerDesigner将PDM导出生成WORD文档或者html文件

    a)         使用PowerDesigner打开pdm文件 b)         点击Report Temlates 制作模板 点击PowerDesigner菜单栏“Report” -> ...

  9. PowerDesigner将PDM导出生成WORD文档--温习老知识

    转:http://www.cnblogs.com/wudiwushen/archive/2010/05/13/1734812.html 今天的温习老知识,是如何将一个PD设计的PDM来导出WORD文档 ...

  10. Java Web项目中使用Freemarker生成Word文档

    Web项目中生成Word文档的操作屡见不鲜.基于Java的解决方式也是非常多的,包含使用Jacob.Apache POI.Java2Word.iText等各种方式,事实上在从Office 2003開始 ...

随机推荐

  1. Go语言net/http包源码学习

    0.前言 该笔记为笔者第一次学习go的net/http包源码的时候所记,也许写的并不是很精确,希望大家多多包涵,一起讨论学习. 该笔记很大程度的参考了网名为"小徐先生"的前辈所分享 ...

  2. JUC (Java Util Concurrency) 基础内容概述

    目录[-] 转自:http://www.goldendoc.org/2011/05/juc/ 1. JUC概况 2. 原子操作 3. 指令重排 4. Happens-before法则:(Java 内存 ...

  3. .NET9 - Swagger平替Scalar详解(四)

    书接上回,上一章介绍了Swagger代替品Scalar,在使用中遇到不少问题,今天单独分享一下之前Swagger中常用的功能如何在Scalar中使用. 下面我们将围绕文档版本说明.接口分类.接口描述. ...

  4. Python 爬虫必备杀器,xpath 解析 HTML

    最近工作上写了个爬虫,要爬取国家标准网上的一些信息,这自然离不了 Python,而在解析 HTML 方面,xpath 则可当仁不让的成为兵器谱第一. 你可能之前听说或用过其它的解析方式,像 Beaut ...

  5. 阿里巴巴LangEngine开源了!支撑亿级网关规模的高可用Java原生AI应用开发框架

    LangEngine作为阿里集团内部发起的纯Java版本的AI应用开发框架,经过充分实践,已经广泛应用于包括淘宝.天猫.阿里云.爱橙科技.菜鸟.蚂蚁.飞猪.1688.LAZADA等在内的多个业务场景. ...

  6. 记一次cenos7安装nginx

    安装依赖 yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel 下 ...

  7. 在 MySQL 创造类似 PipelineDB 的流视图(continuous view)

    公司的系统采用的是 Google Cloud SQL 提供的 MySQL 数据库,由于历史原因,数据库成本极高,需要对它进行优化缩减成本. 相比 PostgresSQL,MySQL 主要缺少以下特性, ...

  8. 序列化与反序列化的概念、基于django原生编写5个接口、drf介绍和快速使用、cbv源码分析

    目录 一.序列化反序列化 二.基于django原生编写5个接口 三.drf介绍和快速使用 概念 安装 代码 四.cbv源码分析 一.序列化反序列化 api接口开发,最核心最常见的一个过程就是序列化,所 ...

  9. ubuntu安装ps命令

    docker容器是debian的镜像,没有ps命令,查个进程没法查. 安装procps包 apt-get install procps

  10. Qt编写地图综合应用22-动态轨迹

    一.前言 上一篇文章写道拿到路径规划的轨迹点坐标集合,并且已经可以通过调用addPolyline绘制线段的形式将轨迹点绘制,接下来就是要如何动态的绘制这些轨迹点,最简单的方法就是开个定时器挨个取出下一 ...