freemarker
概述
FreeMarker是一款模板引擎,即能够基于模板和要改变的数据,来生成输出文本(比如html网页、电子邮件、配置文件、源代码等)的通用工具。

入门案例
springboot整合freemarker,生成的静态文件作为mvc视图返回
导入依赖
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | <dependencies><dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 <version>2.3.9.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-freemarker</artifactId>
 <version>2.3.9.RELEASE</version>
 </dependency>
 
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <version>2.3.9.RELEAS</version>
 </dependency>
 
 <dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>1.18.1</version>
 </dependency>
 
 
 <dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-io</artifactId>
 <version>1.3.2</version>
 </dependency>
 </dependencies>
 
 | 
设置配置文件
application.yml
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | spring:application:
 name: freeMarker-demo
 freemarker:
 cache: false
 settings:
 template_update_delay: 0
 suffix: .ftl
 server:
 port: 9000
 
 | 
创建模板文件
在resources下创建templates,此目录为freemarker的默认模板存放目录
在templates文件夹下创建模板文件f1.ftl
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | <!DOCTYPE html><html>
 <head>
 <meta charset="utf-8">
 <title>Hello World!</title>
 </head>
 <body>
 <b>普通文本 String 展示:</b><br><br>
 Hello ${name} <br>
 <hr>
 <b>对象Student中的数据展示:</b><br/>
 姓名:${stu.name}<br/>
 年龄:${stu.age}
 <hr>
 </body>
 </html>
 
 | 
创建模板类
| 12
 3
 4
 5
 6
 7
 
 | @Datapublic class Student {
 private String name;
 private int age;
 private Date birthday;
 private Float money;
 }
 
 | 
编写controller层代码
将freeMarker生成的静态文件作为视图返回
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | @Controllerpublic class FreeMarkerController {
 
 @GetMapping("/fHello")
 public String fHello(Model model){
 model.addAttribute("name","李白");
 Student stu = new Student();
 stu.setName("张飞");
 stu.setAge(28);
 model.addAttribute("stu",stu);
 return "f1";
 }
 }
 
 | 
访问页面
访问http://localhost:9000/fHello

原理分析




可以通过在application.yml中更改默认文件夹和文件后缀名
freeMarker的指令和语法
基础语法
注释
<#-- -->,介于其之间的内容会被freemarker忽略
插值
${}部分的内容,freemarker会用真实值去替换
FTL指令
和html中的标签类似,名字前加#以示区分,freemarker会解析标签中的表达式或逻辑
文本
直接写的内容,是表示仅文本信息,这些内容不会被freemarker解析,而是直接将内容输出
常用指令
集合指令—List
<#list></#list>
实例
Java代码
| 12
 3
 4
 5
 6
 7
 8
 
 | @GetMapping("/fList")public String fList(Model model){
 List<Student> list = new ArrayList<>();
 list.add(new Student("李白",28,new Date(),27.92f));
 list.add(new Student("曹操",68,new Date(),2007.92f));
 model.addAttribute("stus",list);
 return "list";
 }
 
 | 
模板内容
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | <h2>学生信息列表</h2><table>
 <tr>
 <th>序号</th>
 <th>姓名</th>
 <th>年龄</th>
 <th>生日</th>
 <th>钱包</th>
 </tr>
 <#list stus as stu> <#--stu为stus里面的每一个元素 -->
 <tr>
 <td>${stu_index+1}</td> <#-- stu_index表示当前元素索引 -->
 <td>${stu.name}</td>
 <td>${stu.age}</td>
 <td>${stu.birthday?datetime}</td> <!-- 日期类型数据必须指定数据类型-->
 <td>${stu.money}</td>
 </tr>
 </#list>
 </table>
 
 | 
哈希数据—map
如何获取map里面元素的值
- 方式一:map[keyname].properties
- 方式二:map.keyname.properties
实例
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | @GetMapping("/fMap")public String fMap(Model model){
 Map<String,Student> map = new HashMap<>();
 Student stu1 = new Student("李白",28,new Date(),27.92f);
 Student stu2 = new Student("曹操",68,new Date(),2007.92f);
 map.put("stu1",stu1);
 map.put("stu2",stu2);
 model.addAttribute("stusMap",map);
 return "map";
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | <h2>集合元素</h2><hr/>
 <h4>学生1的信息</h4>
 <p>name:${stusMap.stu1.name}</p>
 <p>age:${stusMap.stu1.age}</p>
 <p>birthday:${stusMap.stu1.birthday?datetime}</p>
 <p>money:${stusMap.stu1.money}</p>
 
 <h4>学生2的信息</h4>
 <p>name:${stusMap["stu2"].name}</p>
 <p>age:${stusMap["stu2"].age}</p>
 <p>birthday:${stusMap["stu2"].birthday?datetime}</p>
 <p>money:${stusMap["stu2"].money}</p>
 
 | 
遍历map
- <#list>map?keys as key</#list>
map?keys获取map所有的键列表
实例
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | @GetMapping("/fMapLsit")public String fMapList(Model model){
 Map<String,Student> map = new HashMap<>();
 Student stu1 = new Student("李白",28,new Date(),27.92f);
 Student stu2 = new Student("曹操",68,new Date(),2007.92f);
 map.put("stu1",stu1);
 map.put("stu2",stu2);
 model.addAttribute("stusMap",map);
 return "mapList";
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | <h2>集合元素</h2><hr/>
 
 <#list stusMap?keys as key>
 <h4>学生${key_index+1}的信息</h4>
 <p>name:${stusMap[key].name}</p>
 <p>age:${stusMap[key].age}</p>
 <p>birthday:${stusMap[key].birthday?datetime}</p>
 <p>money:${stusMap[key].money}</p>
 </#list>
 
 | 
if指令
| 12
 3
 4
 5
 
 | <#if 条件语句>
 <#else>
 
 <#if>
 
 | 
实例
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | <h2>集合元素</h2><hr/>
 
 <#list stusMap?keys as key>
 <#if stusMap[key].age gte 40> <#-- 年龄大于40的用红色表示 -->
 <div style="color: red">
 <h4>学生${key_index+1}的信息</h4>
 <p>name:${stusMap[key].name}</p>
 <p>age:${stusMap[key].age}</p>
 <p>birthday:${stusMap[key].birthday?datetime}</p>
 <p>money:${stusMap[key].money}</p>
 </div>
 <#else>
 <div>
 <h4>学生${key_index+1}的信息</h4>
 <p>name:${stusMap[key].name}</p>
 <p>age:${stusMap[key].age}</p>
 <p>birthday:${stusMap[key].birthday?datetime}</p>
 <p>money:${stusMap[key].money}</p>
 </div>
 </#if>
 
 </#list>
 
 | 
运算符
算数运算符
- 加法: +
- 减法: -
- 乘法: *
- 除法: /
- 求模 (求余): %
注意:
除了 + 运算以外,其他的运算只能和 number 数字类型的计算
比较运算符
- =或者- ==:判断两个值是否相等.
- !=:判断两个值是否不等.
- >或者- gt:判断左边值是否大于右边值
- >=或者- gte:判断左边值是否大于等于右边值
- <或者- lt:判断左边值是否小于右边值
- <=或者- lte:判断左边值是否小于等于右边值
注意:
- =和- !=可以用于字符串、数值和日期来比较是否相等
- =和- !=两边必须是相同类型的值,否则会产生错误
- 字符串 "x"、"x "、"X"比较是不等的.因为FreeMarker是精确比较
- 其它的运行符可以作用于数字和日期,但不能作用于字符串
- 使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符
- 可以使用括号来避免这种情况,如:<#if (x>y)>
逻辑运算符
注意:
逻辑运算符只能作用于布尔值,否则将产生错误 
空值处理
判断某变量是否存在使用 ??
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | <h2>集合元素</h2><hr/>
 
 <#if stusMap??> <#--判断stusMap是否存在-->
 <#list stusMap?keys as key>
 <#if (stusMap[key].age >= 40)>
 <div style="color: red">
 <h4>学生${key_index+1}的信息</h4>
 <p>name:${stusMap[key].name}</p>
 <p>age:${stusMap[key].age}</p>
 <p>birthday:${stusMap[key].birthday?datetime}</p>
 <p>money:${stusMap[key].money}</p>
 </div>
 <#else>
 <div>
 <h4>学生${key_index+1}的信息</h4>
 <p>name:${stusMap[key].name}</p>
 <p>age:${stusMap[key].age}</p>
 <p>birthday:${stusMap[key].birthday?datetime}</p>
 <p>money:${stusMap[key].money}</p>
 </div>
 </#if>
 
 </#list>
 </#if>
 
 | 
缺失变量默认值使用 !
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | <!DOCTYPE html><html>
 <head>
 <meta charset="utf-8">
 <title>Hello World!</title>
 </head>
 <body>
 <#-- 注释部分 -->
 <b>普通文本 String 展示:</b><br><br>
 Hello ${name!'王虎'} <br> <#--当变量name不存在时,默认替换为王虎-->
 <hr>
 <b>对象Student中的数据展示:</b><br/>
 姓名:${stu.name}<br/>
 年龄:${stu.age}
 <hr>
 </body>
 </html>
 
 | 
内建函数
内建函数语法格式: 变量+?+函数名称  
获取某个集合的大小
${集合名?size}
日期相关
显示年月日: ${today?date}
显示时分秒:${today?time}
显示日期+时间:${today?datetime}
自定义格式化:  ${today?string("yyyy年MM月")}
内建函数c
model.addAttribute(“point”, 102920122);
point是数字型,使用${point}会显示这个数字的值,每三位使用逗号分隔。
如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出
${point?c}
将json字符串转成对象
text?eval
| 12
 3
 4
 
 | <#-- assign的作用是创建一个新的变量 --><#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
 <#assign data=text?eval />
 开户行:${data.bank}  账号:${data.account}
 
 | 
freeMaker静态文件生成
在mvc中支持将freemarker静态文件作为视图返回前端,但是在一些场景中,需要将生成的静态文件输出存储在本地
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | package com.bang;
 
 import com.bang.entity.Student;
 import freemarker.template.Configuration;
 import freemarker.template.Template;
 import freemarker.template.TemplateException;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 
 @SpringBootTest
 public class TestFreeMarker {
 
 @Autowired
 private Configuration configuration;
 
 @Test
 public void testGenerateFile() throws IOException, TemplateException {
 
 Template template = configuration.getTemplate("mapList.ftl");
 
 
 Map<String, Student> map = new HashMap<>();
 Student stu1 = new Student("李白",28,new Date(),27.92f);
 Student stu2 = new Student("曹操",68,new Date(),2007.92f);
 map.put("stu1",stu1);
 map.put("stu2",stu2);
 
 Map<String, Object> params = new HashMap<>();
 params.put("stusMap",map);
 
 
 
 template.process(params, new FileWriter("./test.html"));
 }
 }
 
 |