前言
java操作world文档,实现world内容的新增、替换、模板合并等操作。
提示:本项目使用springboot进行开发
一、poi-tl介绍?
poi-tl是基于Apache POI的一套拥有简洁API的跨平台的模板引擎,纯Java组件,是Java Word的模板引擎,对docx格式的文档增加模板语法,支持对段落、页眉、页脚、表格等模板替换,并且提供了插件机制,在文档的任何地方做任何事情。
所有的语法结构都是以 {{ 开始,以 }} 结束。
{{template}} 普通文本
{{@template}} 图片
{{#template}} 表格
{{*template}} 列表
{{+template}} Word文档合并
说白了就是把你要替换、新增的东西用{{xxx}}进行补充,然后通过代码自动给你实现替换。这样做的目的就是通过代码去解决实际中需要批量录入的一些问题,当然也支持对world文档进行美化、合并、页眉页脚等等操作。
官方git:https://github.com/Sayi/poi-tl
二、使用步骤
1.需要提前准备好要操作的world文档
需要对模板world文档提前进行替换准备
2.需要提前准备好springboot框架
3.开始进行maven的pom引入
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.1</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
这里补充说明一下,因为poi-tl内部引用的log4j版本过低,导致我项目启动有报错,所以外部新引入了log4j的依赖。
4.读入word模板
我是通过流读取的文件,然后自定义一个实体,实现了{{xxx}}的字段填充。这只是一种做法,可以通过查阅它的API借助其他方式,也有通过文件路径的等等方式。
如果你需要操作的world文档比较多,可以借助循环调用实现多文档的操作,具体就根据业务来就行呢。
private static NiceXWPFDocument autoFullText(String path, TemplateUser templateUser) throws Exception {
InputStream inputStream = Files.newInputStream(Paths.get(path));
NiceXWPFDocument document = XWPFTemplate.compile(inputStream).render(templateUser).getXWPFDocument();
IOUtils.closeQuietly(inputStream);
return document;
}
补充说明:{{xxx}}这里面可以通过一个实体,去控制我们要填充的具体字段,比如你要录入name、sex、age等信息,完全可以通过面向对象,定义一个Student实体类,然后设置这些属性,poi-tl会自动去匹配你实体里面的各个属性,很方便快捷。
但是有一点需要注意,实体中的属性名字最好都是小写,我在测试的时候发现如果按照驼峰命名,可能会报错格式不正确,无法正常解析的问题!
5.合并多份world为一份world模板
有的时候,需要对一些模板进行合并操作,比如将2份world合并为1份整体world.这个poi-tl也是支持的。
这里我贴出了一个static方法,参数就是多份world文档,NiceXWPFDocument这个就是poi-tl识别的world文档格式,然后我们通过取出里面的主模板,然后追加其他world模板在这个模板之后就可以了。
private static NiceXWPFDocument mergeTemplates(List<NiceXWPFDocument> templates) throws Exception {
NiceXWPFDocument document = templates.get(0);
templates.remove(document);
log.info("主模板需要合并的其他模板数:{}", templates.size());
for (NiceXWPFDocument template : templates) {
document.getXWPFDocument().createParagraph().createRun().addBreak(BreakType.PAGE);
document = document.merge(template);
template.close();
}
log.info("主模板合并完毕");
return document;
}
补充说明:在for循环里面,设置了一个addBreak(BreakType.PAGE),这个就是分页的作用,因为多份world文档,需要在合并的时候,都是从新的一页开始追加的,做到互不影响。
6.响应前端下载以及前端上传代码
考虑到有些朋友可能用到文件的下载,我也就一并贴出代码了。
前端用的vue2+axios,纯html的,不是vue-cli脚手架哈,请求的地址是你后端自己的接口,具体的接收那些就不赘述了。
vue js中的methods调用
methods: {
async submitForm(formName) {
this.fullscreenLoading = true;
//获取模板节点id
this.ruleForm.department = this.$refs.tree.getCheckedKeys();
const result = await axiosPostRequest('/templates/autoFill', this.ruleForm);
if (result !== '') {
this.fullscreenLoading = false;
this.$message.success('模板制作成功');
let binaryData = [];
binaryData.push(result.data);
const objectUrl = window.URL.createObjectURL(new Blob(binaryData))
const link = document.createElement("a");
link.href = objectUrl;
link.setAttribute("download", '模板文件.docx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
this.fullscreenLoading = false;
this.$message.error('生成模板失败');
}
}
}
axios调用
//axios封装post请求
function axiosPostRequest(url, data) {
return axios.post(url, data, {responseType: 'blob'})
.then(res => {
return res;
})
.catch(err => {
console.log(err)
return ''
})
}
后端完成模板解析后,响应前端的代码。这里只是贴了一部分,不是完整的function,仅供参考,也是为大家提供一下响应头的一些信息。HttpServletResponse response。
response.setContentType("application/octet-stream");
String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
response.setHeader("Content-disposition", "attachment;filename=\"" + "Document" + format + ".docx" + "\"");
out = response.getOutputStream();
bos = new BufferedOutputStream(out);
worlds.write(bos);
bos.flush();
out.flush();
PoitlIOUtils.closeQuietlyMulti(worlds, bos, out);
总结
本次讲述,只是针对poi-tl的一些功能点进行了讲解,其实它的功能也是很强大的,基于poi进行了增强,基本的操作world也就足够了。有兴趣的小伙伴可以直接去官网查阅更详细的功能,比如生成table表单。设置images图片,填充页眉页脚等等。
以上文章可以给大家提供学习思路与解决问题的办法,作为分享,欢迎大家阅读点赞,如有问题也欢迎批评指正,一起学习进步。