根据模板动态生成word(一)使用freemarker生成word
@
一、准备模板
1、创建模板文件
首先先建立一个word文件,输入模板内容freemaker的内容,下面是本次演示的word文件。

然后将word文件另存为 .xml 文件,然后再把文件后缀改成.ftl 。将项目的resource目录下建立一个templates目录(非必须步骤)将 模板文件放到templates目录下


打开模板文件按 Ctrl + Shift + L 将模板内容格式化。
2、处理模板
2.1 处理普通文本
处理文本比较简单,将需要替换文本中直接用占位符 ${} 替换即可。
这里发现一个问题因为之前在word格式时我就已经替换了变量,但是在ftl变量却被 拆分成多段了(见图1)。但是这样是freemaker是无法成功替换变量的,所以需要手动处理成到一个段里(如图2),关于这点实在太无语了,因为没有找到比较好的处理办法,只能手工处理,在实际的开发工作中曾经花了几个小时来做这件事情。
图1:

图2

2.2 处理表格
如果模板里需要用变量填充表格,建议模板里的表格像word文件一样建一个两行的表格。在模板中<<w:tbl>> 表示一个表格 、<w: tr> 表示一行、<w: tc> 表示一列。因为FreeMarker 是利用列表一行一行循环填充的,所以我们可以根据关键字找到<<w:tbl>>标签,因为第一个 <w: tr>是表头注意不要改到了,找到第二个<w: tr>在前后分别加上如下语句即可,后面的表格里后面的行<w: tr>需要删掉,建议模板里的表格像word文件一样建一个两行的表格即可这样就不用删了:
<#list itemList as item>
</#list>
替换后的模板如下:

2.3 处理图片
如果模板里需要用变量填充图片,建议先在word文件里插入一张图片,这样在模板文件里找到<pkg:binaryData>标签直接里面把里面的图片base64字符替换成变量即可,word里可以通过植入base64字符来展示图片:
替换前:

替换后:
<pkg:binaryData>${image1}</pkg:binaryData>
到此模板已经调整完成,接下来就可以开始写代码了。
二、项目代码
1、引入依赖
在项目的pom文件里引入如下依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
2、生成代码
将图片转成Base64字符串的公共方法:
public static String getImageBase64Str(String imgFile) {
try( InputStream in = new FileInputStream(imgFile)) {
byte[] data = new byte[in.available()];
in.read(data);
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
根据模板文件生成word,主要生成的word的文件后缀必须是doc不能是docx,不然生成的文件无法打开。
public static void crateWord(Map<String, Object> dataMap, String templatePath, String targetFile){
String path = templatePath.substring(0,templatePath.lastIndexOf("/"));
String templateName = templatePath.substring(templatePath.lastIndexOf("/") + 1);
try (FileOutputStream out = new FileOutputStream(targetFile);
Writer writer = new BufferedWriter(new OutputStreamWriter(out, "utf-8"))){
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(FreeMakerTest.class, path);
//除了ClassForTemplateLoading外,另一种模板加载方式DirectoryForTemplateLoading,也可用
//ClassPathResource resource = new ClassPathResource(path);
//configuration.setDirectoryForTemplateLoading(resource.getFile());
//加载模板
Template template = configuration.getTemplate(templateName);
//渲染模板
template.process(dataMap, writer);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (TemplateException e) {
throw new RuntimeException(e);
}
}
三、验证生成word
新建的列表数据实体类:
public class Arrears{
private String name;
private Integer num;
private String endDay;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public String getEndDay() {
return endDay;
}
public void setEndDay(String endDay) {
this.endDay = endDay;
}
}
准备模板填充数据
private static Map<String, Object> prepareParam(){
LocalDate currentDate = LocalDate.now();
LocalDate endDate = currentDate.plusYears(1L);
List<Arrears> arrearsList = new ArrayList<>();
arrearsList.add(new Arrears(){{setName("一顿老魏");setNum(1);setEndDay("三月内");}});
arrearsList.add(new Arrears(){{setName("贵州大黄牛");setNum(1);setEndDay("一年内");}});
arrearsList.add(new Arrears(){{setName("v我50");setNum(1);setEndDay("一月内");}});
//填充所需要的数据
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("debtor", "陈有楚");
dataMap.put("nowYear", String.valueOf(currentDate.getYear()));
dataMap.put("nowMonth", String.valueOf(currentDate.getMonthValue()));
dataMap.put("nowDay", String.valueOf(currentDate.getDayOfMonth()));
dataMap.put("arrears", "一顿老魏、贵州大黄牛、v我50");
dataMap.put("endYear", String.valueOf(endDate.getYear()));
dataMap.put("endMonth", String.valueOf(endDate.getMonthValue()));
dataMap.put("endDay", String.valueOf(endDate.getDayOfMonth()));
dataMap.put("arrearsList", arrearsList);
dataMap.put("image1", getImageBase64Str("D:\\picture\\其他\\24-05-23-142418.png"));
dataMap.put("creditor", "知北游");
return dataMap;
}
测试代码:
public static void main(String[] args) throws IOException {
//准备参数
Map<String, Object> dataMap = prepareParam();
crateWord(dataMap,"/templates/qiantiao.ftl","D:\\test\\qiantiao.doc");
}
测试结果:

根据模板动态生成word(一)使用freemarker生成word的更多相关文章
- freemarker动态生成word并将生成的word转为PDF,openoffice转换word乱码
之前项目有个需求,需要先动态生成word内容,然后再预览生成word的内容(不能修改).整理一下,方便以后使用. 网上参考了好多大神的博客.具体也忘了参考谁的了,如有侵权,请告知修改. 思路一: 将目 ...
- JSP利用freemarker生成基于word模板的word文档
利用freemarker生成基于word模板的word文档 freemarker简介 FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与Web容器 ...
- 通过freemarker生成一个word,解决生成的word用wps打开有问题的问题,解决出word时中文文件名乱码问题,解决打开出word时打开的word出现问题的问题,出图片,解决动态列表
通过freemarker制作word比较简单 步骤:制作word模板.制作方式是:将模板word保存成为xml----在xml的word模板中添加相应的标记----将xml的word文件的后缀名 ...
- 使用freemarker生成word,步骤详解并奉上源代码
1. 步骤 1. 用word编辑好模板 1. 普通字符串替换为 ${string} 2. 表格循环用标签 <#list userList as user> 姓名:${user.u ...
- Freemaker基于word模板动态导出压缩文件汇总整理
Freemaker基于word模板动态导出压缩文件汇总整理 Freemaker基于word模板动态导出单个文件思路和代码详情见连接: https://www.cnblogs.com/lsy-blogs ...
- Freemaker基于word模板动态导出汇总整理
Freemaker基于word模板动态导出汇总整理 一.使用的jar包: 二.Word模板动态导出的基本思路: 1.首先通过自己在word中创建好需要导出的word文本+表格的模板,模板中需要填写内容 ...
- freemarker 生成word
一.生成模板,动态获取的部分用${变量名},然后将word另存为xml文件,再将后缀名改成ftl格式.然后将模板放在对应的目录下. 二.引入freemarker包,mawen引用 <depend ...
- 我是如何使用freemarker生成Word文件的?
推荐:亲身体验,数次踩坑,遂撰写此文,以备各位不时之需. 背景 一天,产品经理递给我了一份word报告,我定睛一看 这个文档有大大小小的标题层级,还有排版好的段落.各种一目了然的饼图.走势图,当然还少 ...
- FreeMarker生成word的代码
用于生成word用的freemarker工具类 package com.ucap.netcheck.utils; import java.io.File; import java.io.File ...
- FreeMarker生成Word文档
FreeMarker简介: FreeMarker是一款模板引擎:即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页.电子邮件.配置文件.源代码等)的通用工具,它不是面向最终用户的,而是一个 ...
随机推荐
- python中的类继承
""" """ class Animal(object): def __init__(self,name,food): self.name ...
- $el,$nextTick,$set
this.$el this.$el DOM的根元素 => 是一个完全唯一的 $el 直到组件挂载完成 (mounted) 之前都会是 undefined. 对于单一根元素的组件,$el 将会指向 ...
- OI 数论中的上界估计与时间复杂度证明
预备 0.1 渐进符号 其实不少高等数学 / 数学分析教材在讲解无穷小的比较时已经相当严谨地介绍过大 O.小 O 记号,然而各种历史习惯记法的符号滥用(abuse of notation)[1] 直到 ...
- 数据库mysql8.0安装+Navicat12
第一次写博客,准备坚持下去把每天学习到的东西记录下来,刚好安装mysql8.0过程中遇到了一些问题并解决,系统win10.致敬博客 首先先粘贴一段mysql的百度百科词条:MySQL是一个关系型数据库 ...
- .Net性能测试工具BenchmarkDotNet学习
.Net性能测试工具BenchmarkDotNet学习 BenchmarkDotNet 是一个用于性能基准测试的开源框架.它可以让开发人员编写简单易懂的代码,并测量和分析这些代码的性能表现,从而帮助开 ...
- Django笔记三十之log日志记录详解
本文首发于公众号:Hunter后端 原文链接:Django笔记三十之log日志的记录详解 这一节介绍在 Django 系统里使用 logging 记录日志 以下是一个简单的 logging 模块示例, ...
- vue2.x/vue3.0中使用ts
vue2.x(vue-cli3)中使用ts https://www.jianshu.com/p/3cbcdd766295 https://www.cnblogs.com/xiaohuizha ...
- Hardhat 开发框架 - Solidity开发教程连载
Decert.me 要连载教程了, <Solidity 开发教程> 力求系统.深入的介绍 Solidity 开发, 同时这是一套交互式教程,你可以实时的修改教程里的合约代码并运行. 本教程 ...
- 2021-01-03:java中,描述一下什么情况下,对象会从年轻代进入老年代?
福哥答案2021-01-03: 1.对象的年龄超过一定阀值,-XX:MaxTenuringThreshold 可以指定该阀值.2.动态对象年龄判定,有的垃圾回收算法,比如 G1,并不要求 age 必须 ...
- Alist云盘视频加密助手:支持云盘视频文件加密与在线播放,不用再担心视频文件被和谐了!
在当前娱乐资源丰富的时代,人们每天都在接触各种视频资源.然而,网盘限速.版权审核.视频分级.少儿不宜等问题经常让人感到困扰.如何在保护隐私的前提下,让视频存储和分享变得更加便捷.安全呢?分享一款实用的 ...