springBoot借助poi-tl实现word生成
目录
准备工作
文本的简单实现
图片的简单实现
表格的简单实现
表格的实现
表格循环的实现
列表的简单实现
统计图表的实现
多系列表的方式
单系列表的方式
组和图表的实现
页码的实现
目录的实现
poi-tl官方地址:
扩展(需要借助其他框架实现)
html写入到word中
水印的实现
目录的实现
这是一个国人开发的框架,感觉编码习惯更加复合国人吧,而且模板定义和使用起来确实挺方便的
准备工作
- 我们需要引入poi-tl的jar包
com.deepoove poi-tl 1.10.0
- 注意:还要引入对应版本的poi的jar包
org.apache.poi poi 4.1.2 org.apache.poi poi-ooxml 4.1.2 org.apache.poi poi-ooxml-schemas 4.1.2
文本的简单实现
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 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 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 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
http://deepoove.com/poi-tl
扩展(需要借助其他框架实现)
我们的poi-tl主要专注于文档模板处理,如动态替换文本、插入表格等,所以有些功能是无法实现的或支持不好,比如水印,html的写入,目录的实现,可以借助poi-tl扩展框架poi-tl-ext,也可以直接借助其他第三方框架
html写入到word中
我们需要使用一些在poi-tl上的扩展插件,可以引用poi-tl-ext插件
io.github.draco1023 poi-tl-ext 0.4.2
HtmlRenderPolicy(还可以用来处理html的表格)
模板中还是使用{{xxxxx}}作为占位符(这里就省略了)
html字符串
String FIRE_EXTINGUISHER= new String("
一.测试一号
1)宋体且红色
2)宋体且黑色
3)宋体黑色
4)宋体且蓝色
");将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实现不了添加水印)
e-iceblue spire.doc.free 5.2.0
代码实现(注意,如果使用的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");
效果
-
- 注意:还要引入对应版本的poi的jar包