🔍 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
  • 数字(0false,非 0true
  • 字符串(空字符串 ""false,非空为 true
  • 集合(ListMap 等,空集合为 false
  • 日期、对象等(nullfalse

🛠️ 二、操作步骤(非常详细)

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