根据模板动态生成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网页.电子邮件.配置文件.源代码等)的通用工具,它不是面向最终用户的,而是一个 ...
随机推荐
- day39:MySQL:查询操作之单表查询&多表查询&子查询
目录 part1:单表查询 1.where条件的使用 2.group 子句 分组分类 3.having 数据在分类分组之后,进行二次数据过滤 4.order by 排序, 按照什么字段进行排序 5.l ...
- Active Record 活动记录
ActiveRecord活动记录类 一.声明AR类(模型层) namespaceapp\models; useyii\db\ActiveRecord; classCustomer extends Ac ...
- Linux(二)文件权限和压缩
1 搜索查找类 1.1 查找定位文件 find <搜索范围.路径> <选项> find将从指定目录下递归地遍历其各个子目录,将满足条件的文件显示在终端. 选项说明 -name: ...
- 理解Java程序的执行
main 方法 public class Solution { public static void main(String[] args) { Person person = new Person( ...
- Go中的有限状态机FSM的详细介绍
1.FSM简介 1.1 有限状态机的定义 有限状态机(Finite State Machine,FSM)是一种数学模型,用于描述系统在不同状态下的行为和转移条件. 状态机有三个组成部分:状态(Stat ...
- 机器学习(七):梯度下降解决分类问题——perceptron感知机算法与SVM支持向量机算法进行二维点分类
实验2 感知机算法与支持向量机算法 一.预备知识 1.感知机算法 二.实验目的 掌握感知机算法的原理及设计: 掌握利用感知机算法解决分类问题. 三.实验内容 设计感知机算法求解, 设计SVM算法求解( ...
- ntp导致其他线程卡顿原因总结
这个是在项目开发中遇到的一个比较严重的问题,第一影响到主界面的播放卡顿,第二影响到我这边线程同样卡顿,按道理来说两个没有数据交互的线程应该没有任何影响,改为detach模式也没用,最后定位到居然是单独 ...
- [C++提高编程] 3.4 案例-评委打分
文章目录 3.4 案例-评委打分 3.4.1 案例描述 3.4.2 实现步骤 3.4 案例-评委打分 3.4.1 案例描述 有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除 ...
- [人脸活体检测] 论文:Learn Convolutional Neural Network for Face Anti-Spoofing
[人脸活体检测] 论文:Learn Convolutional Neural Network for Face Anti-Spoofing 论文简介 这是最早期CNN用于活体检测的文章,在此之前都是手 ...
- 一天吃透SpringBoot面试八股文
Springboot的优点 内置servlet容器,不需要在服务器部署 tomcat.只需要将项目打成 jar 包,使用 java -jar xxx.jar一键式启动项目 SpringBoot提供了s ...