springBoot借助poi-tl实现word生成
这是一个国人开发的框架,感觉编码习惯更加复合国人吧,而且模板定义和使用起来确实挺方便的。
目录
这是一个国人开发的框架,感觉编码习惯更加复合国人吧,而且模板定义和使用起来确实挺方便的
准备工作
-
我们需要引入poi-tl的jar包
<dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.10.0</version> </dependency> -
注意:还要引入对应版本的poi的jar包
<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>
文本的简单实现
1.定义poi-tl的word模板
- 在poi-tl中定义模板很简单,只需要使用{{xxxx}}作为占位符即可,然后存储word文件,放到项目中就可以直接使用

2.然后就可以直接定义代码实现根据当前模板生成word文件了
-
@SpringBootTest public class PoiTlTest { @Test public void test() { try { //获取模板文件地址(根据自己的文件位置定义) String path = PoiTlTest.class.getResource("/word/test.docx").toURI().getPath(); //定义填充内容和对应关系 Map<String, Object> map = new HashMap<>(); map.put("title", "标题党"); map.put("body", "内容党"); XWPFTemplate template = XWPFTemplate.compile(path).render(map); //生成新的模板(根据自己想要生成的文件位置定义) template.writeAndClose(new FileOutputStream( "src/main/resources/word" + "/test2.docx")); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } } }
3.运行,得到填充后的word
图片的简单实现
1.图片的填充,使用的是{{@xxx}}定义的,注意前面有个@,否则会是对象的地址值

2.代码实现
方式一:可以直接在value中定义图片的路径实现(只是简单的方式,不能进行复杂的操作)
String iamgeStream = PoiTlTest.class.getResource("/word/111.png").toURI().getPath();
map.put("image", iamgeStream);
XWPFTemplate template = XWPFTemplate.compile(path).render(map);
方式二:借助poi-tl提供的PictureRenderData的方式创建(可以进行复杂操作,比如大小,旋转,边框的控制)
String iamgeStream = PoiTlTest.class.getResource("/word/111.png").toURI().getPath();
//第一个为图片宽,第二个为高,第三个图片类型,第四个输入流
PictureRenderData pictureRenderData = new PictureRenderData(100, 100, iamgeStream);
//将图片也放入到map中
map.put("image", pictureRenderData);
XWPFTemplate template = XWPFTemplate.compile(path).render(map);
如果我们想用图片的原有大小,而不是手动可以使用下面的方式获取图片的又有大小,然后使用
// 获取图片的原始宽度和高度
BufferedImage read = ImageIO.read(new File(iamgeStream));
int width = read.getWidth();
int height = read.getHeight();
3.写入后

4.图片的替换
图片的引用标签(可以替换图片,且不会影响图片的样式和大小等)
首先要插入图片,然后定义可选文字
office定义

wps的方式我没找到怎么给图片设置可选文字
代码实现,需要借助Pictures类
String iamgeStream = PoiTlTest.class.getResource("/word/111.png").toURI().getPath();
map.put("imageStyle", Pictures.ofLocal(iamgeStream).create());
实现

表格的简单实现
表格的实现
1.直接通过{{#xxxxxx}}的方式定义一个占位符,这个就是代表这是一个表格(我们直接将手动绘制的表格替换这个占位符)

2.定义我们表格的绘制代码(这里要借助TableRenderData对象)
String[][] table = {
new String[]{"姓名", "性别"},
new String[]{"爱国", "16"},
new String[]{"爱党", "35"}
};
TableRenderData tableRenderData = Tables.of(table).create();
map.put("table",tableRenderData);
3.结果

4.合并单元格
没有数据的用null表示,然后在TableRenderData中控制合并的位置
横着的
String[][] table = {
new String[]{"姓名", "性别","地址"},
new String[]{"爱国", "16","未来"},
new String[]{"爱党", "35","富强"},
new String[]{"爱家庭", null,null}
};
TableRenderData tableRenderData = Tables.of(table)
.mergeRule(MergeCellRule
.builder()
//前面的参数指的从哪里开始,后面的指的结束(纵坐标,横坐标)
.map(MergeCellRule.Grid.of(3, 0), MergeCellRule.Grid.of(3, 2))
.build()
)
.create();
map.put("table",tableRenderData);

竖着的
只需要修改纵坐标和横坐标,和对应的数据为null即可
.map(MergeCellRule.Grid.of(1, 2), MergeCellRule.Grid.of(3, 2))

5.还有种表格的方式,我们的数据都来自一个对象,可以这样定义

代码实现
Student student = new Student("中国的未来", 25,"未来");
map.put("student", student);
实现

表格循环的实现
(下面的是行表格的实现,列表格是在第一个列中定义{{xxx}},其他是一致的)
用到了poi-tl的插件功能
首先定义表格,我们要在表格中定义我们表格的对象集合占位符{{xxx}},然后在表中定义对象的字段占位符[xxxx],两者都要有(这里好像是这样的)

首先定义一个实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
class Student{
private String name;
private Integer age;
private String address;
}
创建填充的对象集合数据,且添加到map中
//1.学生数据
List<Student> students = new ArrayList<>();
Student e = new Student("靓仔", 17, "中国台湾");
Student e2 = new Student("帅哥", 18, "上海");
students.add(e);
students.add(e2);
map.put("students", students);
定义我们需要进行表格的绑定的key
//创建行循环策略
LoopRowTableRenderPolicy rowTableRenderPolicy = new LoopRowTableRenderPolicy();
//告诉模板引擎,要在employees做行循环,绑定行循环策略
Configure configure = Configure.builder().bind("students", rowTableRenderPolicy).build();
将上面的configure作为参数放到tempalte中
//相对于文本和图片,多传入了一个configure参数
XWPFTemplate template = XWPFTemplate.compile(path,configure).render(map);
实现

列表的简单实现
首先定义我们列表的模板,使用{{*xxxxx}}的方式代表是个列表

实现也很好实现,借助Numbering对象,放入到map中即可
写法一:手动加入
map.put("list", Numberings.create("秦","叔","宝"));
写法二:传入集合(转为数组传入)
List<String> list = new ArrayList<>();
list.add("13456");
list.add("134567");
list.add("1345678");
//转化为数组
String[] array = list.toArray(new String[list.size()]);
map.put("list", Numberings.create(array));
实现

我们的列表结构还可以指定
列表类型
DECIMAL
//1. 2. 3.
DECIMAL_PARENTHESES
//1) 2) 3)
BULLET
//● ● ●
LOWER_LETTER
//a. b. c
LOWER_ROMAN
//i ⅱ ⅲ
UPPER_LETTER
//A. B. C.
代码实现
通过指定Numberings.of(NumberingFormat)指定类型,然后需要使用addItem进行添加
Numberings.NumberingBuilder numberingBuilder = Numberings.of(NumberingFormat.DECIMAL);
for (String s : array) {
numberingBuilder.addItem(s);
}
NumberingRenderData numberingRenderData = numberingBuilder.create();
map.put("list", numberingRenderData);
实现

统计图表的实现
首先导入一个图表,然后需要设置图表的可选文字{{xxx}}格式(用的都是引用标签的方式)
office(我用到可选文字的地方都会用office的方式,下面有wps的设置可选文字步骤)

office版本不同,可能位置不同,也可以通过下面的方式查找

wps的方式

需要借助ChartMultiSeriesRenderData对象
多系列表的方式
多系列图表指的是条形图(3D条形图)、柱形图(3D柱形图)、面积图(3D面积图)、折线图(3D折线图)、雷达图、散点图等。
ChartMultiSeriesRenderData chart = Charts
.ofMultiSeries("图表的名称", new String[] { "一月", "二月" })//代表横坐标和图表名称
//addSeries表示的是增加纵坐标,这里三个就是三个纵坐标,其中第二个参数是和上面的横坐标对应的,所以一定要数量对应
.addSeries("蔬菜", new Double[] { 15.0, 6000.0 })
.addSeries("水果", new Double[] { 223.0, 119.0 })
.addSeries("百货",new Double[] { 33.0, 23.0 })
.create();
ap.put("chart", chart);
实现

单系列表的方式
单系列图表指的是饼图(3D饼图)、圆环图等。

代码实现,需要借助ChartSingleSeriesRenderData对象(和多类型图表不一样)
ChartSingleSeriesRenderData pieChart = Charts
.ofSingleSeries("图标的名称", new String[] { "一月", "二月","三月" })
.series("销量", new Integer[] { 999, 666,66 })
.create();
map.put("pieChart", pieChart);
实现:

组和图表的实现
组合图表指的是由多系列图表(柱形图、折线图、面积图)组合而成的图表。

代码实现,他需要借助ChartMultiSeriesRenderData对象
ChartMultiSeriesRenderData chartMultiSeriesRenderData = Charts
.ofComboSeries("图表的名称", new String[]{"啦啦啦", "德玛西亚"})//横坐标和图名
.addBarSeries("柱状图1", new Double[]{15.0, 6.0})//表示的柱状图
.addBarSeries("柱状图2", new Double[]{60.0, 90.0})
.addBarSeries("柱状图3", new Double[]{90.0, 110.0})
.addLineSeries("折线图1", new Double[]{120.0, 290.0})//表示的折线图
.addLineSeries("折线图2", new Double[]{300.0, 130.0})
.create();
map.put("combChart", chartMultiSeriesRenderData);
实现

页码的实现
这个只需要在word中设置好页面,不需要我们操作,word会自动增加页码
目录的实现
目录借助poi-tl提供的new TOCRenderPolicy()只能实现office的,而且客户每次打开都要点击一下,不方便,
解决方法可以借助spire.doc框架,这个相对于来说生成目录比较方便,下面扩展目录下中有实现步骤
poi-tl官方地址:
还有很多功能,这里不在介绍,可以通过官方文档进行学习
http://deepoove.com/poi-tl[这里是图片026]http://deepoove.com/poi-tl
扩展(需要借助其他框架实现)
我们的poi-tl主要专注于文档模板处理,如动态替换文本、插入表格等,所以有些功能是无法实现的或支持不好,比如水印,html的写入,目录的实现,可以借助poi-tl扩展框架poi-tl-ext,也可以直接借助其他第三方框架
html写入到word中
我们需要使用一些在poi-tl上的扩展插件,可以引用poi-tl-ext插件
<dependency>
<groupId>io.github.draco1023</groupId>
<artifactId>poi-tl-ext</artifactId>
<version>0.4.2</version>
</dependency>
HtmlRenderPolicy(还可以用来处理html的表格)
模板中还是使用{{xxxxx}}作为占位符(这里就省略了)
html字符串
String FIRE_EXTINGUISHER= new String("<h2><span style="font-size: 20px; font-family: 宋体; ">一.测试一号</span></h2><p style="text-indent: 24pt;"><span style="font-family: 宋体;font-size: 16px;color: red">1)宋体且红色</span></p><p style="text-indent: 24pt;"><span style="font-family: 宋体;font-size: 16px;">2)宋体且黑色</span></p><p style="text-indent: 24pt;"><span style="font-family: 宋体;font-size: 16px;">3)宋体黑色</span></p></p><p style="text-indent: 24pt;"><span style="font-family: 宋体;font-size: 16px;color: blue;">4)宋体且蓝色</span></p>");
将html字符串放到到map中
map.put("htmlTest",htmlTest);
定义数据和插件绑定,且使用
Configure configure = Configure.builder().bind("htmlTest", new HtmlRenderPolicy()).build();
XWPFTemplate template = XWPFTemplate.compile(path, configure).render(map);
实现

poi-tl插件的使用,如果是多个的话,可以通过下面的方式定义
Configure config = Configure.builder().build();
config.customPolicy("xxx", new HtmlRenderPolicy());
config.customPolicy("xxx", new TOCRenderPolicy());
水印的实现
需要借助spire.doc框架(poi-tl实现不了添加水印)
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc.free</artifactId>
<version>5.2.0</version>
</dependency>
代码实现(注意,如果使用的poi-tl生成的word,一定要等poi-tl生成文档后,对生成的新word进行加水印)
// 加载现有的Word文档
Document document = new Document();
document.loadFromFile("src/main/resources/word" + "/test2.docx");
TextWatermark txtWatermark = new TextWatermark();// 创建文本水印
txtWatermark.setText("这是一个大大的水印");//设置文本水印格式
txtWatermark.setFontName("仿宋");//字体
txtWatermark.setFontSize(28);//字号
txtWatermark.setColor(Color.red);//颜色
txtWatermark.setLayout(WatermarkLayout.Diagonal);//文字倾斜角度 此处使用斜对角
txtWatermark.setSemitransparent(true);//半透明
document.setWatermark(txtWatermark);// 将文本水印应用到文档
// 保存修改后的文档
document.saveToFile("src/main/resources/word" + "/test2.docx", FileFormat.Docx);
效果图

水印图片的实现
Document document = new Document();
document.loadFromFile("src/main/resources/word" + "/test2.docx", FileFormat.Docx);
PictureWatermark picture = new PictureWatermark();
String iamgeStream2 = PoiTlTest.class.getResource("/word/111.png").toURI().getPath();
picture.setPicture(iamgeStream2);
picture.setScaling(150);
picture.isWashout(false);
document.setWatermark(picture);
document.saveToFile("src/main/resources/word" + "/test2.docx", FileFormat.Docx);
效果

目录的实现
也是借助spire.docx框架
我们要在word模板中插入一个目录用来表示目录的位置,然后我们要将作为目录的内容设置称标题,只有被设置成标题才会被识别且生成目录
代码实现(会自动生成)
Document dd = new Document();
dd.loadFromFile("src/main/resources/word" + "/test2.docx", FileFormat.Docx);
dd.updateTableOfContents();
dd.saveToFile("src/main/resources/word" + "/test2.docx");
效果

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)