字符集问题
像其它大多数的Java应用程序一样,FreeMarker使用 "UNICODE 文本"(UTF-16)来工作。 不过,也有必须处理 字符集 的情况, 因为它不得不和外界交换数据,这就会使用到很多字符集。
输入的字符集
当 FreeMarker 要加载模板文件(或没有解析的文本文件)时,
那就必须要知道文件使用的字符集,因为文件的存储是原生的字节序列。
可以使用 encoding
配置 来确定字符集。
这个配置项只在 FreeMarker 使用 Configuration
对象的 getTemplate
方法加载模板(解析过的或没有解析过的)时起作用。请注意 include
指令
在内部也使用了这个方法,所以 encoding
的值对一个已经加载的模板,而且如果这个模板包含 include
指令的调用来说很重要。
encoding
配置的getter和setter方法在第一个(配置)层面很特殊。
getter方法猜想返回值是基于 Locale
(本地化,译者注)传递的参数;
它在地图区域编码表(称为编码地图)中查询编码,如果没有找到该区域,就返回默认编码。
可以使用配置对象的 setEncoding(Locale locale, String encoding)
方法来填充编码表;编码表初始化时是空的。默认的初始编码是系统属性
file.encoding
的值,但是可以通过
setDefaultEncoding
方法来设置一个不同的默认值,而不是依赖它。
对于新项目来说,默认的编码设置就是 utf-8
。
也可以在模板层或运行环境层(当指定编码值作为 getTemplate
方法的参数时,应该在模板层覆盖 encoding
设置)直接给定值来覆盖
encoding
的设置。如果不覆盖它,那么 locale
设置的有效值将会是 configuration.getEncoding(Locale)
方法的返回值。
而且,代替这种基于字符集猜测的机制,也可以在模板文件中使用
ftl
指令, 比如 <#ftl
encoding="utf-8">
来指定特定的字符集。
请注意,模板使用的字符集和模板生成的输出内容的字符集是独立的 (除非包含 FreeMarker 的软件故意将设置输出内容的字符集和模板字符集设置成相同的)。
输出的字符集
Note:output_encoding
设置/参数和 内建函数url
从FreeMarker 2.3.1版本开始才可以使用,而在2.3以前的版本中是不存在的。
原则上,FreeMarker 不处理输出内容的字符集问题,
因为 FreeMarker 将输出内容都写入了 java.io.Writer
对象中。而 Writer
对象是由封装了 FreeMarker(比如Web应用框架) 的软件生成的,
那么输出内容的字符集就是由封装软件来控制的。而FreeMarker有一个称为
output_encoding
(开始于 FreeMarker 2.3.1 版本之后)的设置。
封装软件应该使用这个设置(Writer
对象使用的字符集)
来通知 FreeMarker 在输出中(否则 FreeMarker 不能找到它)使用哪种字符集。
有一些新的特性,如内建函数url
,特殊变量output_encoding
也利用这个信息。因此,如果封装软件没有设置字符集这个信息,
那么 FreeMarker 需要知道输出字符集的特性就不能被利用了。
如果你使用 FreeMarker 来编写软件, 你也许想知道在输出内容中到底选择了哪种字符集。 当然这取决于运行 FreeMarker 输出内容的计算机本身, 但是如果用户对这个问题可以变通, 那么通用的实践是使用模板文件的字符集作为输出的字符集,或者使用UTF-8。 通常使用UTF-8是最佳的实践,因为任意的文本可能来自数据模型, 那就可能包含不能被模板字符集所编码的字符。
如果使用了
Template.createProcessingEnvironment(...)
和 Environment.process(...)
方法来代替
Template.process(...)
方法,
FreeMarker 的设置可以对任意独立执行的模板进行。
因此,你可以对每个独立执行的模板设置 output_encoding
信息:
Writer w = new OutputStreamWriter(out, outputCharset); Environment env = template.createProcessingEnvironment(dataModel, w); env.setOutputEncoding(outputCharset); env.process();