如何将FreeMarker配置对象动态输出到另一ftl文件的script块中
FreeMarker 配置对象输出到JS全局变量解决方案
核心实现思路
不需要手动遍历配置对象,直接使用FreeMarker内置能力或者通用递归序列化逻辑,天然支持配置层级动态扩展。
标准实现方案(FreeMarker 2.3.20及以上版本)
步骤1:确认变量作用域传递
你在page.ftl中导入config.ftl后,需要将配置对象暴露到全局作用域,避免引入OutputScript.ftl时出现变量跨作用域无法访问的问题:
<!-- page.ftl 代码 --> <#import "config.ftl" as cfg> <!-- 将配置对象设为全局变量,子模板可直接访问 --> <#global globalConfig = cfg.config> <#include "OutputScript.ftl">
如果不想用全局变量,也可以在引入子模板时通过参数传递:
<#include "OutputScript.ftl" params={"globalConfig": cfg.config}>
步骤2:在OutputScript.ftl中序列化输出
直接使用FreeMarker内置的?json_encode指令序列化配置对象,该指令会自动处理字符串转义、类型适配、任意层级的嵌套结构,配置新增层级无需修改代码:
<!-- OutputScript.ftl 代码 --> <script> window.object = window.object || {}; // 直接序列化输出,自动适配所有配置层级 window.object.config = ${globalConfig?json_encode}; </script>
低版本兼容方案(无?json_encode能力)
如果你的FreeMarker版本低于2.3.20,没有内置序列化能力,可以使用如下通用递归序列化宏,天然支持任意层级的配置扩展:
<!-- 可以将该宏放到公共工具ftl文件中全局复用 --> <#macro serializeToJson obj> <#if obj?is_string> "${obj?js_string}" <#elseif obj?is_boolean || obj?is_number> ${obj} <#elseif obj?is_hash> {<#list obj?keys as key> "${key?js_string}": <@serializeToJson obj=obj[key]/><#if key_has_next>,</#if> </#list>} <#elseif obj?is_sequence> [<#list obj as item> <@serializeToJson obj=item/><#if item_has_next>,</#if> </#list>] <#elseif obj?is_nil> null <#else> "${obj?js_string}" </#if> </#macro> <!-- OutputScript.ftl 中调用 --> <script> window.object = window.object || {}; window.object.config = <@serializeToJson obj=globalConfig/>; </script>
常见问题排查
- 输出JS语法报错:不要手动给序列化结果加引号,
?json_encode和自定义宏已经自动处理字符串包裹和特殊字符转义 - 变量未定义:不要直接跨import命名空间访问变量,导入
config.ftl后需要通过别名访问配置对象,比如cfg.config而不是直接写config - 输出有多余空白:可以在序列化后加
?trim处理,比如${globalConfig?json_encode?trim}
内容的提问来源于stack exchange,提问作者Romain
相关产品推荐
相关产品推荐

