FreeMarker 是一个强大的 Java 模板引擎,广泛用于后端渲染、代码生成、报告生成等场景。在 FreeMarker 中,除了基本的变量输出和逻辑控制外,exists
、eval
、replace
、split
是一些非常实用的操作,尤其在处理动态数据和字符串时非常关键。
一、核心概念
操作 |
说明 |
exists |
判断变量是否存在或是否为非空值 |
eval |
动态解析字符串为 FreeMarker 表达式 |
replace |
字符串替换操作 |
split |
字符串分割操作 |
这些操作常用于模板中对数据进行处理,使模板逻辑更灵活。
二、操作步骤详解
1. exists
:判断变量是否存在或非空
语法
<#if variable?? && variable != "">
变量存在且非空
<#else>
变量不存在或为空
</#if>
步骤详解
- 使用
??
判断变量是否定义(存在)。
- 使用
!= ""
判断字符串是否为空。
- 常与
<#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}
步骤详解
- 定义一个字符串变量,内容为表达式。
- 使用
?eval
对其进行求值。
- 可用于动态访问变量。
示例
<#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")}
步骤详解
- 使用
?replace
方法。
- 第一个参数为要替换的内容。
- 第二个参数为替换后的内容。
示例
<#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>
步骤详解
- 使用
?split
方法。
- 参数为分隔符。
- 返回值为列表(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>
六、参考资料