🔍 FreeMarker 条件判断 <#if> <#elseif> <#else>
全面指南
📚 一、核心概念
1.1 什么是 FreeMarker 条件判断?
FreeMarker 使用 <#if>
、<#elseif>
、<#else>
指令实现 模板中的逻辑分支控制,类似于 Java 中的 if-else if-else
。
它允许你在模板中根据数据模型的值,动态决定渲染哪部分内容。
1.2 核心指令
指令 |
说明 |
<#if condition> |
判断条件是否为真 |
<#elseif condition> |
多条件分支(可多个) |
<#else> |
默认分支(可选) |
</#if> |
结束 if 块 |
1.3 支持的数据类型判断
FreeMarker 支持对以下类型进行条件判断:
- 布尔值(
true
/ false
)
- 数字(
0
为 false
,非 0
为 true
)
- 字符串(空字符串
""
为 false
,非空为 true
)
- 集合(
List
、Map
等,空集合为 false
)
- 日期、对象等(
null
为 false
)
🛠️ 二、操作步骤(非常详细)
2.1 准备环境
确保已集成 FreeMarker(参考前文),并准备好模板文件(.ftl
)和 Java 数据模型。
2.2 创建模板文件 condition.ftl
<!DOCTYPE html>
<html>
<head>
<title>FreeMarker 条件判断示例</title>
</head>
<body>
<h2>条件判断演示</h2>
<!-- 1. 基础 if-else -->
<#if user.age >= 18>
<p>${user.name} 是成年人。</p>
<#else>
<p>${user.name} 是未成年人。</p>
</#if>
<!-- 2. 多条件 elseif -->
<#if score >= 90>
<p>成绩:优秀</p>
<#elseif score >= 80>
<p>成绩:良好</p>
<#elseif score >= 60>
<p>成绩:及格</p>
<#else>
<p>成绩:不及格</p>
</#if>
<!-- 3. 判断字符串 -->
<#if status == "active">
<p>状态:激活中</p>
<#elseif status == "inactive">
<p>状态:已停用</p>
<#else>
<p>状态:未知</p>
</#if>
<!-- 4. 判断集合是否为空 -->
<#if userList??>
<#if userList?size == 0>
<p>用户列表为空</p>
<#else>
<ul>
<#list userList as user>
<li>${user}</li>
</#list>
</ul>
</#if>
<#else>
<p>用户列表不存在</p>
</#if>
<!-- 5. 判断变量是否存在 -->
<#if name?exists>
<p>姓名:${name}</p>
<#else>
<p>姓名:匿名用户</p>
</#if>
<!-- 6. 使用 ! 提供默认值 -->
<p>邮箱:${email!"未填写"}</p>
</body>
</html>
2.3 Java 数据模型准备
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.*;
import java.util.*;
public class ConditionDemo {
public static void main(String[] args) {
try {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
cfg.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));
cfg.setDefaultEncoding("UTF-8");
Template template = cfg.getTemplate("condition.ftl");
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("score", 85);
dataModel.put("status", "active");
// 用户对象
Map<String, Object> user = new HashMap<>();
user.put("name", "张三");
user.put("age", 17);
dataModel.put("user", user);
// 用户列表
List<String> userList = Arrays.asList("Alice", "Bob", "Charlie");
dataModel.put("userList", userList);
// 可选字段
dataModel.put("name", "李四");
// email 未设置,使用默认值
Writer out = new OutputStreamWriter(System.out);
template.process(dataModel, out);
} catch (IOException | TemplateException e) {
e.printStackTrace();
}
}
}
2.4 输出结果
<p>张三 是未成年人。</p>
<p>成绩:良好</p>
<p>状态:激活中</p>
<ul>
<li>Alice</li>
<li>Bob</li>
<li>Charlie</li>
</ul>
<p>姓名:李四</p>
<p>邮箱:未填写</p>
⚠️ 三、常见错误与解决方案
错误 |
原因 |
解决方法 |
Expected a boolean expression |
条件表达式不是布尔值 |
检查变量类型,使用 ?? 或 ?exists |
Variable not found |
变量未定义 |
使用 ?? 或 ! 提供默认值 |
Mismatched directive |
<#if> 未正确闭合 |
确保有 </#if> |
Unexpected token |
语法错误(如少 > ) |
检查 <#if > 语法 |
NullPointerException |
变量为 null 且未判断 |
使用 ?exists 或 ?? |
📝 四、注意事项
项目 |
说明 |
条件表达式必须是布尔值 |
不支持 if (1) 这种“真值”判断(不像 JavaScript) |
使用 ?exists 判断变量是否存在 |
比 ?? 更安全 |
使用 ! 提供默认值 |
${var!"default"} |
避免在模板中做复杂逻辑 |
条件判断应简单,复杂逻辑放在 Java 层 |
字符串比较使用 == |
"active" == status |
数字比较支持 > , < , >= , <= , == , != |
|
支持逻辑运算符 |
&& (and)、|| (or)、! (not) |
🧪 五、使用技巧
技巧 |
示例 |
判断变量是否存在 |
<#if name?exists> |
提供默认值 |
${name!"匿名"} |
判断集合是否为空 |
<#if list?size == 0> 或 <#if list??> |
使用 ?has_content |
<#if list?has_content> 更语义化 |
组合条件 |
<#if age >= 18 && gender == "M"> |
否定判断 |
<#if !(status == "active")> |
使用 ?default |
${status?default("unknown")} |
✅ 推荐使用 ?has_content
替代 ?size == 0
,更高效且语义清晰。
🚀 六、最佳实践与性能优化
6.1 最佳实践
实践 |
说明 |
保持模板逻辑简单 |
条件判断不超过 3 层 |
使用宏封装复杂判断 |
提高可维护性 |
在 Java 层预处理数据 |
如计算状态、等级等 |
使用 ?has_content 判断集合 |
更高效 |
避免嵌套过深的 <#if> |
可拆分为多个宏或模板 |
使用 ?dump 调试 |
<#if data?dump> 查看变量结构 |
6.2 性能优化
优化点 |
说明 |
模板缓存 |
FreeMarker 默认缓存模板,无需手动优化 |
减少条件判断次数 |
复杂逻辑提前在 Java 层处理 |
避免在循环中做复杂判断 |
可提前计算状态 |
使用 ?has_content 而非 ?size |
?has_content 性能更好 |
📚 七、学习建议
阶段 |
建议 |
入门 |
掌握 <#if> <#else> <#elseif> 基本语法 |
进阶 |
学习 ?exists , ?? , ! , ?has_content |
高级 |
结合 <#list> , <#macro> 实现复杂模板 |
实战 |
在 Spring Boot 项目中使用条件判断 |
文档 |
FreeMarker 官方文档 - if |
📌 八、总结
模块 |
内容 |
核心指令 |
<#if> , <#elseif> , <#else> |
支持类型 |
布尔、数字、字符串、集合、对象 |
安全判断 |
?exists , ?? , ! , ?has_content |
常见错误 |
变量未定义、类型不匹配、语法错误 |
注意事项 |
条件必须是布尔值,避免复杂逻辑 |
使用技巧 |
组合条件、默认值、内容判断 |
最佳实践 |
简单逻辑、预处理、宏封装 |
性能优化 |
减少嵌套、使用 ?has_content |