在Freemarker中默认转义

在Freemarker模板中,我们可以使用escape指令自动将转义应用于包含块内的所有插值:

  Hallo, ${name}  

有没有办法以编程方式实现类似的效果,定义应用于模板中所有插值的默认转义,包括那些转义外转义?

谢谢。

详细说明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>", ""); } }; 

如果您未在添加的部分中包含换行符,则不会出现行编号问题。 但是,您无法使用此方法使用<#ftl> / [#ftl]。

从2.3.24开始,每个模板都有一个关联的freemarker.core.OutputFormat对象,该对象指定是否以及如何转义${...} (和#{...} )。 用于HTML,XML和RTF的OuputFormat是开箱即用的,但您也可以定义自己的格式。 当默认情况下所选的OutputFormat转义时,您可以像${foo?no_esc}一样明确地防止转义。

有几种方法可以将模板与所需的OutputFormat相关联。 对于HTML和XML转义,建议的方法是将ftlh配置设置为true ,然后对HTML使用ftlh文件扩展名,为XML模板使用ftlh文件扩展名。 您还可以使用template_configurers设置,基于任意模板名称(模板路径)模式将OutputFormat -s与模板相关联。 最后,您可以像configuration.setOutputFormat(HTMLOutputFormat.INSTANCE)一样全局设置默认输出格式。 您也可以将模板顶部的输出格式覆盖为<#ftl output_format='HTML'> ,但应该很少使用它。

相关文档页面: http : //freemarker.org/docs/dgui_misc_autoescaping.html,http : //freemarker.org/docs/pgui_config_outputformatsautoesc.html

有一个解决方案,虽然它并非完全无足轻重。 您可以创建一个包装其他模板加载器的特殊TemplateLoader,并在模板源文本的序言中注入<#escape x as x?html>,并添加为它的结尾。

明显的缺点: – 第一行中的列号将被抛弃 – 如果您的模板以<#ftl>声明开头,则需要在其后插入<#escape>。

如果您使用<#include parse = false ... />在模板中包含HTML,则链接中建议的TemplateLoaders需要稍微调整一下。

此外,您需要复制spring.ftl并使用您自己的副本,并在顶部删除<#ftl ..>指令,如Tom所说。

以下效果很好,虽然有点粗糙(使用guava over 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); } } 

您实际上不需要WrappingReader来添加转义。 您可以在任何TemplateLoader周围创建一个装饰器,在模板中读入一个String,在escapes中包装模板文本,然后返回一个读取结果String的StringReader。 看看这是怎么做的,看看这里 。 我发现的唯一问题是,如果你使用这种方法并从类路径中包含spring.ftl宏,它们会爆炸,因为它们在最顶层有一个<#ftl>声明。 但是,您可以简单地将spring.ftl复制到模板路径中并删除声明(以及所有转义指令,因为默认情况下您将转义)。