Apache FreeMarker 配置参数详解

系统讲解 Apache FreeMarker Configuration 的核心配置项,涵盖模板加载、默认编码、异常处理器、数字与布尔及日期格式化、本地化查找、输出格式与自动转义策略、空白处理、版本常量以及配置文件的取值与含义。

Apache FreeMarkerApache FreeMarker2026/10/12

Apache FreeMarker 配置参数详解

FreeMarker 的全部运行行为由 freemarker.template.Configuration 对象控制。Configuration 继承自 freemarker.core.Configurable,既提供类型化的 setXxx() 方法,也提供统一的 setSetting(name, value) / setSettings(Properties) 键值接口。本文逐项说明常用配置项的取值与含义,示例基于 FreeMarker 2.3.35 实测。

一、Configuration 创建与版本常量

1.1 创建 Configuration

Configuration cfg = new Configuration(Configuration.VERSION_2_3_35);

Configuration 建议作为单例在整个应用生命周期内复用。

1.2 版本常量 Configuration.VERSION_2_3_x

new Configuration(Version) 接收的版本号决定模板语言的兼容行为(而非运行时库版本)。2.3.35 提供从 VERSION_2_3_0 到 VERSION_2_3_35 的常量。推荐直接使用与依赖一致的版本:

Configuration.VERSION_2_3_35   // 启用 2.3.35 的模板语言行为
Configuration.VERSION_2_3_0    // 向后兼容老模板(不推荐新项目使用)

运行时真实库版本用 Configuration.getVersion() 获取(返回 Version),字符串形式用 Configuration.getVersionNumber();实测均返回 2.3.35。

二、模板加载相关参数

2.1 setDirectoryForTemplateLoading

cfg.setDirectoryForTemplateLoading(new File("templates"));
  • 取值:java.io.File,指向模板所在目录。
  • 含义:以文件系统目录作为模板根,getTemplate("a/b.ftl") 解析为 templates/a/b.ftl。
  • 适用:本地文件、需要热更新模板的场景。
  • 注意:目录必须存在,否则抛 IOException。

2.2 setClassLoaderForTemplateLoading

cfg.setClassLoaderForTemplateLoading(Demo.class.getClassLoader(), "templates");
  • 取值:ClassLoader + 根路径前缀字符串。
  • 含义:从 classpath 加载模板,模板需随构建打进 target/classes/templates/(可在 pom.xml 用 <resource><directory>templates</directory><targetPath>templates</targetPath></resource> 配置)。
  • 适用:打成 JAR 后分发、模板随包发布的场景。
  • 实测:配置后 target/classes/templates/ 下模板可被正常加载并渲染。

两者只能选其一(后设置者生效);也可用 setTemplateLoader(MultiTemplateLoader) 组合多种来源。

2.3 setTemplateUpdateDelayMilliseconds

cfg.setTemplateUpdateDelayMilliseconds(5000);
  • 取值:long,毫秒,默认约 60000(旧接口 setTemplateUpdateDelay(int seconds) 已 deprecated)。
  • 含义:两次检查同一模板是否被修改的时间间隔。设为 0 表示每次都检查(便于开发调试),生产环境应设较大值以降低 I/O。

三、编码与本地化

3.1 setDefaultEncoding

cfg.setDefaultEncoding("UTF-8");
  • 取值:字符集名,推荐 UTF-8。
  • 含义:模板文件读取与输出的默认编码。避免中文乱码应在创建 Configuration 后立即设置(2.3.0 起默认即为 UTF-8,仍建议显式声明)。

3.2 setLocalizedLookup

cfg.setLocalizedLookup(false);
  • 取值:boolean,默认 true。
  • 含义:是否启用本地化模板查找。为 true 时,getTemplate("foo.ftl") 会按当前 Locale 依次尝试 foo_zh_CN.ftl、foo_zh.ftl 等本地化变体;为 false 时只按原名查找,避免意外命中语言变体。

四、输出格式与自动转义

4.1 setOutputFormat

import freemarker.core.HTMLOutputFormat;
cfg.setOutputFormat(HTMLOutputFormat.INSTANCE);
  • 取值:freemarker.core.OutputFormat 实例,jar 内提供 HTMLOutputFormat、XMLOutputFormat、XHTMLOutputFormat、RTFOutputFormat、PlainTextOutputFormat、UndefinedOutputFormat;也可传入字符串 "HTML"、"XML" 等(2.3.24+)。
  • 含义:声明模板默认输出格式,决定 ${...} 是否进行自动转义以及 #ftl output_format 的默认值;调用 unsetOutputFormat() 可恢复默认。
  • 实测对比(同一模板,html 值为 <b>x</b> & 'y'):
输出格式${html} 结果
HTMLOutputFormat.INSTANCE&lt;b&gt;x&lt;/b&gt; &amp; &#39;y&#39;(已转义)
未设置(PlainText)<b>x</b> & 'y'(不转义)

4.2 setAutoEscapingPolicy

cfg.setAutoEscapingPolicy(Configuration.FORCE_AUTO_ESCAPING_POLICY);
  • 取值(int 常量):
    • ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY(默认):输出格式自带自动转义时启用;
    • ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY:只要输出格式支持转义就启用;
    • FORCE_AUTO_ESCAPING_POLICY:强制启用,输出格式不支持则报错;
    • DISABLE_AUTO_ESCAPING_POLICY:关闭自动转义。
  • 含义:控制自动转义的启用强度。
  • 注意:?no_esc 等标记相关内建函数只在标记型输出格式(HTML/XML 等)下可用;在 PlainText 下使用会触发解析异常 ?no_esc can't be used here, as the current output format isn't a markup (escaping) format。

五、格式化参数

5.1 setNumberFormat

cfg.setNumberFormat("0.00");
  • 取值:Java 数字格式串,如 0.00、#,##0、0.###。
  • 含义:所有数字输出的默认格式。
  • 实测:设置 0.00 后,${price}(1234.5)输出 1234.50,连 ${items?size} 也输出 3.00——该设置作用于全局数字插值,列表长度等整数同样被格式化,需留意。

5.2 setBooleanFormat

cfg.setBooleanFormat("yes,no");
  • 取值:"trueValue,falseValue",或用 "c" 表示输出计算机语言风格 true/false。
  • 含义:布尔插值的输出文本。
  • 实测坑点:将值设为 true,false 会被 FreeMarker 视为「等同未设置的历史默认值」,插值 ${active} 直接抛错: Can't convert boolean to string automatically, because the "boolean_format" setting was "true,false", which is the legacy deprecated default ...。 解决方式:改为 yes,no 等显式取值,或在模板用 ${active?c}(实测 ${true?c} → true)。

5.3 setDateFormat / setDateTimeFormat / setTimeFormat

cfg.setDateFormat("yyyy-MM-dd");
cfg.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
cfg.setTimeFormat("HH:mm:ss");
  • 取值:Java 日期格式串。
  • 含义:控制 ${date?date}、${date?datetime}、${date?time} 的默认格式。
  • 实测:${now?date} → 2026-10-11,${now?datetime} → 2026-10-11 23:42:26。
  • 补充:另有 setLocale(Locale) 影响月份名等本地化文本,setSQLDateAndTimeTimeZone 控制 java.sql.* 时区。

六、异常处理

6.1 setTemplateExceptionHandler

import freemarker.template.TemplateExceptionHandler;
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
  • 取值:freemarker.template.TemplateExceptionHandler 常量,常见三种:
    • RETHROW_HANDLER:把异常抛出到调用方(推荐,配合上层统一处理);
    • DEBUG_HANDLER:在输出中插入调试信息后继续;
    • IGNORE_HANDLER:打印日志、跳过出错的插值并继续渲染;
    • 另有 HTML_DEBUG_HANDLER、BIG_HTML_DEBUG_HANDLER。
  • 实测差异(模板含未定义变量 missingVar):
=== RETHROW_HANDLER (threw InvalidReferenceException) ===
=== IGNORE_HANDLER (no throw) ===
Known: ok
Missing:
After: ok

RETHROW_HANDLER 直接抛出 InvalidReferenceException;IGNORE_HANDLER 打印 SEVERE 日志,把出错插值输出为空并继续渲染后续内容。

6.2 setLogTemplateExceptions / setWrapUncheckedExceptions

cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
  • setLogTemplateExceptions(boolean):模板异常是否额外记入日志(使用 RETHROW_HANDLER 时建议关闭以免重复记录)。
  • setWrapUncheckedExceptions(boolean):是否把模板中的受检异常包装为 TemplateException 抛出,便于在 FTL 内统一捕获。

七、空白处理

7.1 setWhitespaceStripping

cfg.setWhitespaceStripping(true);
  • 取值:boolean,默认 true(2.3.27+)。
  • 含义:是否移除模板标记行产生的多余空白与换行,使 FTL 指令不干扰输出布局。设为 false 时 FTL 标签所在行的空白会被原样保留。

八、freemarker.properties 与键值配置

8.1 加载方式

2.3.35 的 Configuration 不再自动读取 classpath 根目录下的 freemarker.properties,需显式加载:

java.util.Properties props = new java.util.Properties();
props.load(new java.io.FileInputStream("freemarker.properties"));
cfg.setSettings(props);          // 批量设置
cfg.setSetting("default_encoding", "UTF-8");  // 单项设置

setSettings(Properties)、setSettings(InputStream)、setSetting(String, String) 均定义在 freemarker.core.Configurable 上。

8.2 常用键名

键名采用小写下划线风格,与 setXxx 一一对应:

键名对应 setter
default_encodingsetDefaultEncoding
output_formatsetOutputFormat
auto_escaping_policysetAutoEscapingPolicy
whitespace_strippingsetWhitespaceStripping
localized_lookupsetLocalizedLookup
template_update_delaysetTemplateUpdateDelayMilliseconds
number_formatsetNumberFormat
boolean_formatsetBooleanFormat
date_formatsetDateFormat
datetime_formatsetDateTimeFormat
time_formatsetTimeFormat
template_exception_handlersetTemplateExceptionHandler
log_template_exceptionssetLogTemplateExceptions
wrap_unchecked_exceptionssetWrapUncheckedExceptions
recognize_standard_file_extensionssetRecognizeStandardFileExtensions

示例 freemarker.properties:

default_encoding=UTF-8
output_format=HTML
auto_escaping_policy=enable_if_default
whitespace_stripping=true
number_format=0.00
boolean_format=yes,no
date_format=yyyy-MM-dd
datetime_format=yyyy-MM-dd HH:mm:ss
template_exception_handler=rethrow
template_update_delay=5000

九、完整配置示例与实测输出

Configuration cfg = new Configuration(Configuration.VERSION_2_3_35);
cfg.setDirectoryForTemplateLoading(new File("templates"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setNumberFormat("0.00");
cfg.setBooleanFormat("yes,no");
cfg.setDateFormat("yyyy-MM-dd");
cfg.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
cfg.setLocalizedLookup(false);
cfg.setWhitespaceStripping(true);
cfg.setTemplateUpdateDelayMilliseconds(5000);

运行(java -Xms256m -Xmx256m -cp "target/classes:$(cat cp.txt)" Demo)真实回显:

=== FreeMarker version: 2.3.35 ===
Hello quzuo!
Items (3.00):
- ALPHA
- BETA
- GAMMA
-- generated for QUZUO --
Price: 1234.50
Active: yes
Now: 2026-10-11 / 2026-10-11 23:42:26
Version: 2.3.35

十、配置要点小结

  • 加载方式:文件目录与 classpath 二选一,按部署形态决定。
  • 编码:始终显式 setDefaultEncoding("UTF-8")。
  • 异常:生产用 RETHROW_HANDLER 并关闭 logTemplateExceptions,交由上层统一处理。
  • 格式化:number_format/boolean_format 是全局性的,注意对整数与布尔的影响;boolean_format 切勿设为 true,false。
  • 转义:HTML 输出务必设置 output_format,让 ${...} 自动转义,防注入。
  • 版本常量:与依赖版本保持一致,如 VERSION_2_3_35。