Javapoi-tl实现导出Word模板并动态渲染数据

Posted 杰肥啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javapoi-tl实现导出Word模板并动态渲染数据相关的知识,希望对你有一定的参考价值。

文章目录

前言

最近做项目的时候会遇到要求要导出以docx格式结尾的报告文件,于是我就在思考有没有一个比较好用的第三方类库能解决在word上渲染数据的问题。之前也尝试用过poi,感觉不大好用,代码比较复杂且没有什么特别好的支持。于是乎在网上搜索了很久,找到了一个第三方组件库还挺好用的,那就是poi-tl

poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你可以非常方便的加入到你的项目中,并且拥有着让人喜悦的特性。

优点

方案移植性功能性易用性
Poi-tlJava跨平台Word模板引擎,基于Apache POI,提供更友好的API低代码,准备文档模板和数据即可
Apache POIJava跨平台Apache项目,封装了常见的文档操作,也可以操作底层XML结构文档不全,这里有一个教程:Apache POI Word快速入门
FreemarkerXML跨平台仅支持文本,很大的局限性不推荐,XML结构的代码几乎无法维护
OpenOffice部署OpenOffice,移植性较差-需要了解OpenOffice的API
html浏览器导出依赖浏览器的实现,移植性较差HTML不能很好的兼容Word的格式,样式糟糕-
Jacob、winlibWindows平台-复杂,完全不推荐使用

缺点

只能操作.docx格式的word,不能操作.doc格式的word。

使用

开发文档参考如下,各种例子都有,比较好上手。

http://deepoove.com/poi-tl/#example-article

这边我挑几个常用的例子拿出来实践一下,复杂的需要跟着文档学习稍微观摩思考。

引入依赖

要参考官网说明,不然会造成版本不一致,运行的时候会报错。

<!-- POI -->		
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>

<!-- poi-tl -->
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.10.0</version>
</dependency>
渲染普通占位符

这里新建一个很普通的template1.docx,内容就是几个简单的占位符,符合场景是工作中有些模板就是固定渲染占位符即可,不需要做任何的改动。

这里我们简单分析一下模板文档可以得到由三个占位符组成,name,age,address。我们很快可以想到要么创建一个实体类或者一个Map来组装这三个参数,接下来直接看代码。

//===================使用Map的方式================================
//创建目标文件
File sourceFile = new File("c:/test/poi-tl/template1.docx");
//构建数据
Map<String, Object> data = new HashMap();
data.put("name", "jiefei");
data.put("age", "18");
data.put("address", "福建福清");
//创建输出流
OutputStream os = new FileOutputStream("c:/test/poi-tl/template1_out.docx");
//最终编译渲染并输出
XWPFTemplate.compile(sourceFile).render(data).writeAndClose(os);

个人觉得这代码量非常少了,而且api的使用非常通俗易懂,另外最关键的是即使你的数据model中没有覆盖模板中的占位符,最终输出的文件里也不会再带有,而是跟Vue框架那样,页面不展示任何东西而已。

上面我只是用Map演示,你也可以创建一个有name,age,address三个属性的实体类,然后render调用也是可以的。

表格渲染

在实际开发中其实我们会遇见两种表格情况的渲染,一种是行循环,一种是列循环,很多小伙伴可能一下子不太懂啥意思,接下来我画个图来演示这两种情况。

行循环情况其实会比列循环情况多,我在项目中很少遇见列循环有用到的话最多一列。这里我举的例子可能不那么合乎情理,可以参考官网的例子看一下。

  • 行循环实现

    先创建一个模板

@Data
@AllArgsConstructor
public class Student 

    //姓名
    private String name;

    //学号
    private String sid;

    //出生日期
    private String birth;

//创建行循环策略
LoopRowTableRenderPolicy rowTableRenderPolicy = new LoopRowTableRenderPolicy();
//告诉模板引擎,要在students做行循环,绑定行循环策略
Configure configure = Configure.builder().bind("students", rowTableRenderPolicy).build();
//创建目标文件
File sourceFile = new File("c:/test/poi-tl/template2.docx");
//构建数据
Map<String, Object> data = new HashMap();

//1.学生数据
List<Student> students = new ArrayList<>();
Student s1 = new Student("小明", "001", "2022-09-01");
Student s2 = new Student("小红", "002", "2022-09-02");
students.add(s1);
students.add(s2);
//2.设置到students字段中
data.put("students", students);

//创建输出流
OutputStream os = new FileOutputStream("c:/test/poi-tl/template2_out.docx");
//最终编译渲染并输出
XWPFTemplate.compile(sourceFile,configure).render(data).writeAndClose(os);

  • 列循环实现

    先创建列循环模板

@AllArgsConstructor
@Data
public class Person 

    //姓名
    private String name;

    //年龄
    private int age;

    //地址
    private String address;

    //爱好
    private String hobby;


//创建行循环策略
LoopColumnTableRenderPolicy rowTableRenderPolicy = new LoopColumnTableRenderPolicy();
//告诉模板引擎,要在students做行循环,绑定行循环策略
Configure configure = Configure.builder().bind("persons", rowTableRenderPolicy).build();
//创建目标文件
File sourceFile = new File("c:/test/poi-tl/template3.docx");
//构建数据
Map<String, Object> data = new HashMap();

//1.学生数据
List<Person> persons = new ArrayList();
Person person1 = new Person("小明",18,"北京海淀", StringUtils.join(Arrays.asList("打篮球","踢足球"),"、"));
Person person2 = new Person("小红",20,"北京昌平", StringUtils.join(Arrays.asList("化妆","逛街"),"、"));
persons.add(person1);
persons.add(person2);

//2.设置到students字段中
data.put("persons", persons);

//创建输出流
OutputStream os = new FileOutputStream("c:/test/poi-tl/template3_out.docx");
//最终编译渲染并输出
XWPFTemplate.compile(sourceFile,configure).render(data).writeAndClose(os);

Net Core DocXCore 实现word模板导出

实际工作中,往往有这样的需求,需要导出word,还有各种各样的样式,于是有了word模板导出。

实现以下几个需求:

1、表单导出

2、表格导出

3、表单表格混合导出

4、实际用例测试

解决方案:

实现是基于NET Core 2.1 ,搜索了各个开源项目最终基于DocX这个开源库,当初实现时发现DocX作者并没有发布Core的版本,最后在Nuget搜索到DocXCore这个包,但是没有GitHub搜索到这个库。

上面还遇到一个坑爹的问题,系统在win运行没问题,一部署到centos导出就挂了,根据错误研究发现里面居然要获取当前登录的用户信息,win系统没有问题,centos报错,于是去掉获取系统用户这块,居然没有源码。

一怒之下,反编译了DocXCore包,移除了获取登录系统代码,最终win和centos都导出正常。

奉上源码地址:https://github.com/deeround/DocXCore

1、表单导出

模板

技术图片

 

代码

 1     public class FormTest
 2     
 3         public static void Test()
 4         
 5             Console.WriteLine($"表单");
 6             Stopwatch sw = new Stopwatch();
 7             Dictionary<string, object> data = new Dictionary<string, object>()
 8             
 9                  "xmmc","测试姓名测试姓名111",
10                  "sqje","1417.4",
11                  "xmdw","博客园Deeround",
12                  "glfs","自行管理方式",
13                  "xmgk","博客园Deeround来函申请办理 应急抢险治理工程项目竣工结(决)算,该项目已完工并通过项目初步验收,现拟按程序采取政府购买服务方式开展评审",
14                  "psyj","",
15                  "gzyq", @"(一)对建设程序进行评审,包括可行性研究报告、初步设计等批准文件的程序性审查。
16 (二)对建设规模、建设标准、可研执行情况等进行评审。
17 (三)对工程投资进行评审,包括工程计量、定额选用、材料价格及费用标准等的评审。
18 (四)对设施设备资进行评审,包括设施设备型号、规格、数量及价格的评审。
19 ",
20                  "wcsx","1. 收到委托书后在10天内报送评审方案,评审完成后需提交评审报告纸质件7份及电子文档。",
21                  "ywcs","伯爵二元",
22                  "lxr","千年  12345678",
23             ;
24 
25             sw.Start();
26             string root = System.AppDomain.CurrentDomain.BaseDirectory;
27             WordHelper.Export(root + Path.Combine("Templates", "temp_form.docx"), root + "temp_form_out.docx", data);
28             sw.Stop();
29             var time = sw.ElapsedMilliseconds;
30             Console.WriteLine($"耗时:time毫秒");
31         
32     

最终效果

技术图片

 2、表格导出

模板

技术图片

 

 

 代码

 1     public class TableListTest
 2     
 3         public static void Test(int count = 10)
 4         
 5             Console.WriteLine($"表格");
 6             Stopwatch sw = new Stopwatch();
 7             IList<Dictionary<string, object>> data = new List<Dictionary<string, object>>();
 8             for (int i = 0; i < count; i++)
 9             
10                 Dictionary<string, object> d = new Dictionary<string, object>()
11                 
12                      "xm","测试"+i.ToString(),
13                      "nl",i,
14                      "xb",""
15                 ;
16                 data.Add(d);
17             
18 
19             Dictionary<string, object> data1 = new Dictionary<string, object>();
20             data1.Add("list", data);
21             sw.Start();
22             string root = System.AppDomain.CurrentDomain.BaseDirectory;
23             WordHelper.Export(root + Path.Combine("Templates", "temp_table_list.docx"), root + "temp_table_list_out.docx", data1);
24             sw.Stop();
25             var time = sw.ElapsedMilliseconds;
26             Console.WriteLine($"耗时:time毫秒");
27         
28     

 

最终效果

技术图片

 

 

 3、表单表格混合导出

模板

技术图片

 

 

 代码

 1 public class FormTableTest
 2     
 3         public static void Test()
 4         
 5             Console.WriteLine($"表单表格混合");
 6             Stopwatch sw = new Stopwatch();
 7             Dictionary<string, object> data = new Dictionary<string, object>()
 8             
 9                  "xmmc","测试姓名测试姓名111",
10                  "sqje","1417.4",
11                  "xmdw","博客园Deeround",
12                  "glfs","自行管理方式",
13                  "xmgk","博客园Deeround来函申请办理 应急抢险治理工程项目竣工结(决)算,该项目已完工并通过项目初步验收,现拟按程序采取政府购买服务方式开展评审",
14                  "psyj","",
15                  "gzyq", @"(一)对建设程序进行评审,包括可行性研究报告、初步设计等批准文件的程序性审查。
16 (二)对建设规模、建设标准、可研执行情况等进行评审。
17 (三)对工程投资进行评审,包括工程计量、定额选用、材料价格及费用标准等的评审。
18 (四)对设施设备资进行评审,包括设施设备型号、规格、数量及价格的评审。
19 ",
20                  "wcsx","1. 收到委托书后在10天内报送评审方案,评审完成后需提交评审报告纸质件7份及电子文档。",
21                  "ywcs","测试处",
22                  "lxr","李  123456",
23             ;
24             //明细数据
25             IList<Dictionary<string, object>> mx = new List<Dictionary<string, object>>();
26             for (int i = 0; i < 10; i++)
27             
28                 mx.Add(new Dictionary<string, object>() 
29                      "a",i,
30                      "b","项目概况表项目概况表项目概况表项目概况表项目概况表",
31                      "c","评审中",
32                 );
33             
34             data.Add("mx", mx);
35             sw.Start();
36             string root = System.AppDomain.CurrentDomain.BaseDirectory;
37             WordHelper.Export(root + Path.Combine("Templates", "temp_form_table.docx"), root + "temp_form_table_out.docx", data);
38             sw.Stop();
39             var time = sw.ElapsedMilliseconds;
40             Console.WriteLine($"耗时:time毫秒");
41         
42     

最终效果

技术图片

4、实例

请看源码

 

简单说明:

采用字符串模板方式替换形式,之前也用过其他方式设置参数,多多少少会遇到些坑,还不如自定义字符串灵活。

#:普通表单关键字使用#包裹

$:表格关键字使用$包裹,里面使用.分割

 

源码下载:

 DocXCore源码地址: https://github.com/deeround/DocXCore

上面demo源码:https://files.cnblogs.com/files/deeround/WordExportDemo.zip

 

以上是关于Javapoi-tl实现导出Word模板并动态渲染数据的主要内容,如果未能解决你的问题,请参考以下文章

freemarker根据模板生成word文件实现导出功能

Net Core DocXCore 实现word模板导出

easypoi导出word表格怎么遍历数据

java freemarker模板 实现word文件导出

java freemarker模板 实现word文件导出

java用poi导出word文档,我要导出一个表格,表格的单元格中还要有一个表格,请问怎么实现