在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>", "#escape>"); } };
如果您未在添加的部分中包含换行符,则不会出现行编号问题。 但是,您无法使用此方法使用<#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复制到模板路径中并删除声明(以及所有转义指令,因为默认情况下您将转义)。