SpringBoot整合freemark动态生成word
前言
在日常工作中可能遇到这样的场景,像一些报告,合同,统计等等,这些word文档都有固定的格式,模板。只需要替换部分的内容数据就可以了,本文使用SpringBoot+freemaker实现这样的功能。
一、新建SpringBoot工程,导入依赖
<dependencies>
<!-- 引入web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot提供了freemarker的starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
二、配置application.yml
#spring.freemarker.allow-request-override: false #是否允许HttpServletRequest属性覆盖(隐藏)控制器生成的同名模型属性。
#spring.freemarker.allow-session-override=false #是否允许HttpSession属性覆盖(隐藏)控制器生成的同名模型属性。
#spring.freemarker.enabled=true # 是否为此技术启用MVC视图解析。
#spring.freemarker.check-template-location: true #是否检查模板位置是否存在。
#spring.freemarker.expose-request-attributes=false # 在与模板合并之前,是否应该将所有请求属性添加到模型中。
#spring.freemarker.expose-session-attributes=false # 在与模板合并之前,是否应该将所有HttpSession属性添加到模型中。
#spring.freemarker.prefer-file-system-access=true # 是否倾向于在加载模板时访问文件系统。文件系统访问允许对模板更改进行热检测。
#spring.freemarker.prefix= # 在构建URL时用于查看名称的前缀。
#spring.freemarker.request-context-attribute= # 所有视图的RequestContext属性的名称。
#spring.freemarker.settings.*= # 传递到FreeMarker配置的知名FreeMarker密钥。
#spring.freemarker.template-loader-path=classpath:/templates/ # 以逗号分隔的模板路径列表。
# 配这几个够了
spring:
freemarker:
cache: false #是否启用模板缓存, 开发时关闭为好
charset: UTF-8 #模板的字符编码
content-type: text/xml; charset=utf-8
expose-spring-macro-helpers: false # 是否公开一个名为“springMacroRequestContext”的RequestContext以供Spring的宏库使用。
suffix: .ftl #在构建URL时附加到查看名称的后缀。
template-loader-path: classpath:/templates/ #多个路径以逗号分隔
三、准备word模板
四、将word另存为xml文件
将word另存为xml文件后复制到项目中类路径的templates文件夹下,修改后缀为.ftl。完成之后打开文件,格式化代码,找到之前写的占位符字符,数字,一一替换,有时需要稍微调整下格式,格式化代码后,应该很好调整。
02占位符分开了,两个<w:r>
留一个就好了。
图片位置类似
五、开始代码
@GetMapping("/test/word")
public void exportWorld() throws IOException {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(this.getClass(), "/templates");
Template template = configuration.getTemplate("freemark生成world测试.ftl");
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("nameA","疤叔");
dataMap.put("nameB","三皮");
dataMap.put("city","大唐");
dataMap.put("district","塔雁");
dataMap.put("number","88");
dataMap.put("area","120");
dataMap.put("useArea","20");
dataMap.put("device","次卧");
dataMap.put("deviceItem","居住");
dataMap.put("month","5");
dataMap.put("beginTime","2020年12月10日");
dataMap.put("endTime","2021年05月10日");
// 无序列表数据
List<String> listA = Arrays.asList("1.擅自将房屋转租、分租、转让、转借、联营、入股或与他人调剂交换的;",
"2.利用承租房屋进行非法活动,损害公共利益的;",
"3. 乙方租用期间,如需要装修,需征得甲方同意,退房时不得拆除装修物,否则甲方有权索赔;",
"4. 合同生效后甲乙双方原则上不得毁约。如有特殊情况,需提前通知对方,否则给对方造成损失由过错方承担。");
dataMap.put("listA",listA);
// 表格数据
Map<String, Object> tableMap = new HashMap<>();
tableMap.put("furniture","电视");
tableMap.put("isProvide","是");
tableMap.put("price","5000");
Map<String, Object> tableMap2 = new HashMap<>();
tableMap2.put("furniture","冰箱");
tableMap2.put("isProvide","是");
tableMap2.put("price","6000");
Map<String, Object> tableMap3 = new HashMap<>();
tableMap3.put("furniture","洗衣机");
tableMap3.put("isProvide","是");
tableMap3.put("price","7000");
Map<String, Object> tableMap4 = new HashMap<>();
tableMap4.put("furniture","马桶");
tableMap4.put("isProvide","否");
tableMap4.put("price","0");
List<Map<String, Object>> listB = Arrays.asList(tableMap,tableMap2,tableMap3,tableMap4);
dataMap.put("listB",listB);
// 图片数据
String path = ResourceUtils.getURL("classpath:").getPath()+"static/aa.jpg";
InputStream in = null;
byte[] data = null;
try {
in = new FileInputStream(path);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e){
e.printStackTrace();
}
BASE64Encoder encoder = new BASE64Encoder();
String picture = encoder.encode(data);
dataMap.put("picture",picture);
// 输出 这里可以替换成响应流
File outFile = new File("freemark已经生成world.doc");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
try {
template.process(dataMap,out);
out.flush();
out.close();
} catch (TemplateException e) {
e.printStackTrace();
}
}
六、结果
到这里就OK了,快去试试吧!