Apache FreeMarker 配置参数详解
系统讲解 Apache FreeMarker Configuration 的核心配置项,涵盖模板加载、默认编码、异常处理器、数字与布尔及日期格式化、本地化查找、输出格式与自动转义策略、空白处理、版本常量以及配置文件的取值与含义。
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 | <b>x</b> & 'y'(已转义) |
| 未设置(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_encoding | setDefaultEncoding |
output_format | setOutputFormat |
auto_escaping_policy | setAutoEscapingPolicy |
whitespace_stripping | setWhitespaceStripping |
localized_lookup | setLocalizedLookup |
template_update_delay | setTemplateUpdateDelayMilliseconds |
number_format | setNumberFormat |
boolean_format | setBooleanFormat |
date_format | setDateFormat |
datetime_format | setDateTimeFormat |
time_format | setTimeFormat |
template_exception_handler | setTemplateExceptionHandler |
log_template_exceptions | setLogTemplateExceptions |
wrap_unchecked_exceptions | setWrapUncheckedExceptions |
recognize_standard_file_extensions | setRecognizeStandardFileExtensions |
示例 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。