# FreeMarker - 教程
# 1. 概述
FreeMarker:
- 一款模板引擎,一个 Java 类库
- 一种基于 模板和要改变的数据,并用来生成文本的通用工具。
- 文档: http://freemarker.foofun.cn/
技术选型对比:
| 技术 | 说明 |
|---|---|
| Jsp | Jsp 为 Servlet 专用,不能单独进行使用 |
| Velocity | Velocity 从 2010 年更新完 2.0 版本后,7 年没有更新。Spring Boot 官方在 1.4 版本后对此也不再支持 |
| thmeleaf | 新技术,功能较为强大,但是执行的效率比较低 |
| freemarker | 性能好,强大的模板语言、轻量 |
# 2. 快速开始
# 2.1. 环境搭建
依赖: (springboot 项目)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
配置:
server:
port: 80
spring:
application:
# 应用名称
name: test-freemarker
freemarker:
# 关闭模板缓存,方便调试
cache: false
# 模板文件的后缀名 (默认 .ftlh)
suffix: .ftl
settings:
# 模板更新的延迟时间,为 0 则没有延迟
template_update_delay: 0
注意:
- freemarker 模板文件的扩展名通常是
ftl,也可以是html、xml、jsp等 - 模板文件默认存放在
resources/templates
# 2.2. 入门案例
controller:
@Controller
public class FreeMarkerController {
@GetMapping("/01-basic")
public String basic(Model model) {
model.addAttribute("name", "张三");
model.addAttribute("stu", Student.of("李四", 18, new Date(), 123.3f));
return "01-basic";
}
}
bean:
@Data
@AllArgsConstructor(staticName = "of")
public class Student {
private String name;
private int age;
private Date birthday;
private Float money;
}
templates/01-basic.ftl:
<#-- 插值表达式 -->
<p>普通文本 String 展示:</p>
<ul>
<li>name: ${ name }</li>
</ul>
<hr>
<p>Student 对象的属性展示: </p>
<ul>
<li>stu.name : ${stu.name}</li>
<li>stu.age : ${stu.age}</li>
</ul>
# 3. 指令语法
基础语法种类
集合指令(List 和 Map)
if 指令
运算符
空值处理
内建函数
# 3.1. 基础语法种类
注释:
<#-- 注释内容, 会被湖绿 -->
插值(表达式):
hello ${ name }
FTL 指令:
<#指令名称></#指令名称>
文本:
<#-- 模板中的普通文本,会直接输出 -->
文本内容
# 3.2. 集合指令
# 3.2.1. List
格式:
<#list 列表名 as 条目名>
列表索引: ${ 条目名_index }
元素的值: ${ 条目名 }
</#list>
示例:
@GetMapping("/02-list")
public String list(Model model) {
List<Student> studentList = new ArrayList<>();
studentList.add(Student.of("张三", 18, new Date(2000, 1, 2), 123.3f));
studentList.add(Student.of("李四", 23, new Date(2002, 10, 28), 456.7f));
model.addAttribute("studentList", studentList);
return "02-list";
}
<table>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>存款</th>
</tr>
<#list studentList as item>
<tr>
<th>${ item_index + 1 }</th>
<th>${ item.name }</th>
<th>${ item.age }</th>
<th>${ item.money }</th>
</tr>
</#list>
</table>
# 3.2.2. Map
语法:
${MAP.属性名}
${MAP["属性名"]}
<#list MAP?keys as 键名变量>
<p>
索引: ${键名变量_index} <br>
属性: ${ MAP[键名变量].属性名 }
</p>
</#list>
示例:
@GetMapping("/03-map")
public String map(Model model) {
Map<String, Object> studentMap = new HashMap<>();
studentMap.put("stu1", Student.of("王五", 28, new Date(2004, 1, 9), 166.7f));
studentMap.put("stu2", Student.of("赵六", 32, new Date(2006, 2, 8), 887.7f));
model.addAttribute("studentMap", studentMap);
return "03-map";
}
<#-- 通过 . 读 map 中的属性 -->
<p>姓名: ${studentMap.stu1.name}</p>
<#-- 通过 [] 读 map 中的属性 -->
<p>年龄: ${studentMap["stu1"].age}</p>
<#-- 遍历 map -->
<#list studentMap?keys as stuMapKey>
<p>
索引: ${ stuMapKey_index } <br>
姓名: ${ studentMap[stuMapKey].name }
</p>
</#list>
# 3.3. if 指令
语法:
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
</#if>
示例:
<#--
相等比较: 使用 “=” 或 “==” 都可以
字符串字面量: 使用 单引号或双引号 界定
-->
<#if student.name = "张三">
<span style="color: red">${ student.name }</span>
<#else>
<span style="color: blue">${ student.name }</span>
</#if>
# 3.4. 运算符
算数运算符:
- 加:
+ - 减:
- - 乘:
* - 除:
/ - 取模:
%
比较运算符:
- 相等:
=或者== - 不相等:
!= - 大于:
>或者gt - 大于或等于:
>=或者gte - 小于:
<或者lt - 小于或等于:
<=或者lte
注意:
==、!=可以用于 字符串、数字、日期 的比较==、!=两边必须是相同类型,否则会报错- 字符串比较是大小写敏感的
- 使用
gt替代>,FreeMarker 会将>解析成标签的结束字符- 可以使用小括号包裹:
<#if (2 > 1)>
- 可以使用小括号包裹:
逻辑运算符:
- 与:
&& - 或:
|| - 非:
!
# 3.5. 空值处理
判断 变量 是否存在:
<#-- wahh 变量不存在 -->
<#if wahh??>
wahh 变量 存在
<#else>
wahh 变量 不存在
</#if>
<br>
<#-- user 变量 为 null -->
<#if user??>
user 变量 不为 null
<#else>
user 变量 为 null
</#if>
默认值:
<#-- 不存在的变量 -->
<p> ${ wahh ! "wahh 不存在!!!" } </p>
<#-- 为 null 的变量 -->
<p> ${ user ! "user 为 null!!!" } </p>
<#-- 嵌套 取值 -->
<p> ${ (user.address.city) ! "user.address.city 更为 null !!!" } </p>
# 3.6. 内建函数
语法:
变量名?函数名称
# 3.6.1. 集合的大小
使用:
${ 集合名?size }
示例:
<p> 集合的大小: ${ studentList ? size } </p>
# 3.6.2. 日期格式化
<#--
model.addAttribute("today", new Date());
-->
<#-- Jan 9, 2026-->
<p>date: ${ today ? date }</p>
<#-- 7:26:38 PM-->
<p>time: ${ today ? time }</p>
<#-- Jan 9, 2026 7:26:38 PM-->
<p>datetime: ${ today ? datetime }</p>
<#-- 2026年01月09日 19时26分38秒-->
<p>string("yyyy年MM月dd日 HH时mm分ss秒"): ${ today ? string("yyyy年MM月dd日 HH时mm分ss秒") }</p>
# 3.6.3. 禁止数字格式化
<#--
model.addAttribute("num", 123456789L);
-->
<#-- 123,456,789 -->
<p>${ 123456789 }</p>
<#-- 123,456,789 -->
<p>${ num }</p>
<#-- 123456789 -->
<p>${ num ? c }</p>
# 3.6.4. JSON字符串转对象
<#-- 定义一个字符串类型的 变量 -->
<#assign userStr="{ 'name': '张三' }" />
<#-- 将 userStr 转换为对象 -->
<#assign userObj=userStr ? eval />
<p> userObj.name : ${ userObj.name } </p>
# 4. 输出解析后的文本
配置:
spring:
freemarker:
# 指定模板所在的目录
template-loader-path: classpath:/templates/ # 默认
使用:
@SpringBootTest
class FreeMarkerDemoApplicationTests {
@Autowired
private Configuration configuration;
@Test
void quickstart() throws Exception {
// 数据
Map<String, Object> data = new HashMap<>();
data.put("msg", "娃哈哈");
// 模板
Template template = configuration.getTemplate("06-static-output.ftl");
// src/main/resources/templates/06-static-output.ftl
// <p>静态化输出: ${ msg }</p>
// 输出
StringWriter out = new StringWriter();
// 处理
template.process(data, out);
String content = out.toString();
System.out.println(content);
//=> <p>静态化输出: 娃哈哈</p>
}
}
# 5. 参考
上一篇: 下一篇:
本章目录