FreeMarker 是一个强大的 Java 模板引擎,广泛用于后端渲染、代码生成、报告生成等场景。在 FreeMarker 中,除了基本的变量输出和逻辑控制外,existsevalreplacesplit 是一些非常实用的操作,尤其在处理动态数据和字符串时非常关键。

一、核心概念

操作 说明
exists 判断变量是否存在或是否为非空值
eval 动态解析字符串为 FreeMarker 表达式
replace 字符串替换操作
split 字符串分割操作

这些操作常用于模板中对数据进行处理,使模板逻辑更灵活。


二、操作步骤详解

1. exists:判断变量是否存在或非空

语法

<#if variable?? && variable != "">
    变量存在且非空
<#else>
    变量不存在或为空
</#if>

步骤详解

  1. 使用 ?? 判断变量是否定义(存在)。
  2. 使用 != "" 判断字符串是否为空。
  3. 常与 <#if> 结合使用进行逻辑判断。

示例

<#assign name = "Alice">
<#if name??>
    名字是:${name}
<#else>
    名字未定义
</#if>

常见错误

  • 忘记使用 ?? 直接访问未定义变量会抛出异常。
  • 对象为空但变量存在时,未判断内容是否为空字符串。

注意事项

  • ?? 仅判断变量是否定义,不判断内容是否为空。
  • 建议使用 ?? && variable != "" 双重判断。

使用技巧

<#assign user = {"name": "", "age": 25}>
<#if user.name??>
    用户名已定义
<#else>
    用户名未定义
</#if>

最佳实践

  • 使用 exists 避免访问未定义变量导致模板渲染失败。
  • 用于控制条件渲染内容,提升模板健壮性。

2. eval:动态解析字符串为表达式

语法

<#assign expr = "user.name">
${expr?eval}

步骤详解

  1. 定义一个字符串变量,内容为表达式。
  2. 使用 ?eval 对其进行求值。
  3. 可用于动态访问变量。

示例

<#assign expr = "user.address.city">
${expr?eval}

常见错误

  • 表达式字符串格式错误,导致 ?eval 抛出异常。
  • 表达式中变量不存在,也会导致错误。

注意事项

  • ?eval 性能略低,建议在必要时使用。
  • 避免将用户输入直接用于 eval,防止注入攻击。

使用技巧

<#assign path = "profile.settings.theme">
<#assign theme = path?eval>
当前主题:${theme}

最佳实践

  • 用于动态访问嵌套对象属性。
  • 用于构建通用模板逻辑,如动态字段渲染。

3. replace:字符串替换

语法

${"Hello World"?replace("World", "FreeMarker")}

步骤详解

  1. 使用 ?replace 方法。
  2. 第一个参数为要替换的内容。
  3. 第二个参数为替换后的内容。

示例

<#assign text = "欢迎来到中国">
${text?replace("中国", "世界")}

常见错误

  • 忘记使用双引号包裹字符串。
  • 替换内容包含特殊字符未转义。

注意事项

  • 替换是区分大小写的。
  • 可以使用正则表达式进行高级替换。

使用技巧

<#assign msg = "error: 404">
${msg?replace("error", "ERROR", "r")}  <!-- 使用 r 表示正则 -->

最佳实践

  • 用于替换敏感词、URL 替换、模板占位符等。
  • 配合正则使用可实现灵活替换逻辑。

4. split:字符串分割

语法

<#assign parts = "apple,banana,orange"?split(",")>
<#list parts as part>
    ${part}
</#list>

步骤详解

  1. 使用 ?split 方法。
  2. 参数为分隔符。
  3. 返回值为列表(sequence),可使用 <#list> 遍历。

示例

<#assign tags = "java,html,css,js"?split(",")>
<#list tags as tag>
    <p>标签:${tag}</p>
</#list>

常见错误

  • 分隔符未正确转义(如正则字符)。
  • 分隔符为空字符串,导致错误。

注意事项

  • 支持正则表达式作为分隔符。
  • 可以指定标志如 "r" 表示正则。

使用技巧

<#assign data = "name:John;age:30;city:Shanghai">
<#list data?split(";") as item>
    <#assign keyVal = item?split(":")>
    ${keyVal[0]} = ${keyVal[1]}
</#list>

最佳实践

  • 用于解析 CSV 数据、键值对字符串等。
  • 结合 list 和嵌套 split 实现复杂结构解析。

三、性能优化建议

操作 性能建议
exists 尽量避免在循环中频繁使用 ??,提前判断
eval 尽量避免在循环中使用,影响性能
replace 多次替换建议合并使用正则
split 若已知结构,建议使用 Java 预处理再传入

四、总结

操作 核心用途 使用建议
exists 判断变量是否存在 用于安全访问变量
eval 动态执行表达式 谨慎使用,防止注入
replace 字符串替换 可配合正则实现复杂替换
split 字符串分割 用于解析结构化字符串

五、完整示例模板

<#-- 定义变量 -->
<#assign user = {"name": "Tom", "email": "tom@example.com", "tags": "java,html,css"}>

<#-- 判断是否存在 -->
<#if user.name?? && user.name != "">
    姓名:${user.name}
</#if>

<#-- 动态 eval -->
<#assign path = "user.email">
当前邮箱:${path?eval}

<#-- 字符串替换 -->
<#assign url = "https://example.com/user/123">
清理路径:${url?replace("/user/123", "/user/456")}

<#-- 字符串分割 -->
<#assign tagList = user.tags?split(",")>
标签列表:
<#list tagList as tag>
    - ${tag}
</#list>

六、参考资料