Javapoi-tl实现导出Word模板并动态渲染数据
Posted 杰肥啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javapoi-tl实现导出Word模板并动态渲染数据相关的知识,希望对你有一定的参考价值。
文章目录
前言
最近做项目的时候会遇到要求要导出以docx格式结尾的报告文件,于是我就在思考有没有一个比较好用的第三方类库能解决在word上渲染数据的问题。之前也尝试用过poi
,感觉不大好用,代码比较复杂且没有什么特别好的支持。于是乎在网上搜索了很久,找到了一个第三方组件库还挺好用的,那就是poi-tl
。
poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你可以非常方便的加入到你的项目中,并且拥有着让人喜悦的特性。
优点
方案 | 移植性 | 功能性 | 易用性 |
---|---|---|---|
Poi-tl | Java跨平台 | Word模板引擎,基于Apache POI,提供更友好的API | 低代码,准备文档模板和数据即可 |
Apache POI | Java跨平台 | Apache项目,封装了常见的文档操作,也可以操作底层XML结构 | 文档不全,这里有一个教程:Apache POI Word快速入门 |
Freemarker | XML跨平台 | 仅支持文本,很大的局限性 | 不推荐,XML结构的代码几乎无法维护 |
OpenOffice | 部署OpenOffice,移植性较差 | - | 需要了解OpenOffice的API |
html浏览器导出 | 依赖浏览器的实现,移植性较差 | HTML不能很好的兼容Word的格式,样式糟糕 | - |
Jacob、winlib | Windows平台 | - | 复杂,完全不推荐使用 |
缺点
只能操作.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模板并动态渲染数据的主要内容,如果未能解决你的问题,请参考以下文章