在 Freemarker 模板中,我们可以使用转义指令自动对包含块内的所有插值应用转义:
<#escape x as x?html>
<#-- name is escaped as html -->
Hallo, ${name}
</#escape>
有没有办法以编程方式实现类似的效果,定义应用于模板中所有插值的默认转义,包括那些外部转义指令?
谢谢。
在 Freemarker 模板中,我们可以使用转义指令自动对包含块内的所有插值应用转义:
<#escape x as x?html>
<#-- name is escaped as html -->
Hallo, ${name}
</#escape>
有没有办法以编程方式实现类似的效果,定义应用于模板中所有插值的默认转义,包括那些外部转义指令?
谢谢。
要详细说明 Attila 的答案:您可以使用这样的类,然后像这样包装您的模板加载器:
final TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), templatePath) {
/**
* Replaces the normal template reader with something that changes the default
* escaping to HTML as to avoid XSS attacks.
*/
@Override
public Reader getReader(Object templateSource, String encoding) throws IOException {
return new WrappingReader(super.getReader(templateSource, encoding), "<#escape x as x?html>", "</#escape>");
}
};
如果您在添加的部分中不包含换行符,则不会出现行号问题。但是,您不能在这种方法中使用 <#ftl>/[#ftl]。
从 2.3.24 开始,每个模板都有一个关联的freemarker.core.OutputFormat
对象,它指定是否以及如何转义${...}
(and )。对于 HTML、XML 和 RTF 是开箱即用的,但您也可以定义自己的格式。默认情况下选定的逃脱时,您可以防止明确逃脱。#{...}
OuputFormat
OutputFormat
${foo?no_esc}
有几种方法可以将模板与OutputFormat
您想要的相关联。对于 HTML 和 XML 转义,推荐的方法是将recognize_standard_file_extensions
配置设置设置为true
,然后使用ftlh
HTML 的ftlx
文件扩展名和 XML 模板的文件扩展名。您还可以OutputFormat
使用设置将 -s 与基于任意模板名称(模板路径)模式的模板相关联template_configurers
。最后同样重要的是,您可以在全局范围内设置默认输出格式,例如configuration.setOutputFormat(HTMLOutputFormat.INSTANCE)
. 您也可以将模板顶部的输出格式覆盖为<#ftl output_format='HTML'>
,尽管它应该很少使用。
相关文档页面: http: //freemarker.org/docs/dgui_misc_autoescaping.html、http : //freemarker.org/docs/pgui_config_outputformatsautoesc.html
如果您使用 <#include parse=false .../> 在模板中包含例如 HTML,则链接中建议的 TemplateLoaders 需要稍作调整。
此外,您需要复制 spring.ftl 并使用您自己的副本,并像 Tom 所说的那样删除顶部的 <#ftl ..> 指令。
以下效果很好,虽然有点粗糙(在 commons-io 上使用番石榴)
@Override
public Reader getReader(Object pTemplateSource, String pEncoding) throws IOException {
Reader tReader = delegate.getReader(pTemplateSource, pEncoding);
try {
String tTemplateText = CharStreams.toString(tReader);
//only include files ending with "ftl", as we may have some parse=false on included html files
if (pTemplateSource.toString().endsWith("ftl")) {
return new StringReader(ESCAPE_PREFIX + tTemplateText + ESCAPE_SUFFIX);
}
return new StringReader(tTemplateText);
} finally {
Closeables.closeQuietly(tReader);
}
}
有一个解决方案,尽管它并不完全是微不足道的。您可以创建一个特殊的 TemplateLoader 来包装其他模板加载器,并在模板源文本的 prolog 中注入 <#escape x as x?html> 并作为其结尾添加。
明显的缺点: - 第一行中的列号将被丢弃 - 如果您的模板以 <#ftl> 声明开头,则需要在其后插入 <#escape>。
您实际上不需要 WrappingReader 来添加转义。您可以在任何 TemplateLoader 周围创建一个装饰器,将模板读入一个字符串,将模板文本包装在转义中,然后返回一个读取结果字符串的 StringReader。要了解这是如何完成的,请查看此处。我发现的唯一问题是,如果您使用这种方法并从类路径中包含 spring.ftl 宏,它们将会爆炸,因为它们在最顶部有一个 <#ftl> 声明。但是,您可以简单地将 spring.ftl 复制到您的模板路径中并删除声明(以及所有转义指令,因为您将默认转义)。