在Freemarker模板中,我们可以使用escape指令自动将转义应用于包含块内的所有插值:
<#escape x as x?html>
<#-- name is escaped as html -->
Hallo, ${name}
</#escape>
有没有办法以编程方式实现类似的效果,定义应用于模板中所有插值的默认转义,包括那些转义外转义?
感谢。
答案 0 :(得分:5)
详细说明Attila的答案:您可以使用像this one这样的类,然后像这样包装模板加载器:
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>");
}
};
如果您在添加的部分中不包含换行符,则不会出现行编号问题。但是,您无法使用此方法使用&lt; #ftl&gt; / [#ftl]。
答案 1 :(得分:4)
自2.3.24起,每个模板都有一个关联的freemarker.core.OutputFormat
对象,该对象指定是否以及如何转义${...}
(和#{...}
)。 HTML,XML和RTF的OuputFormat
开箱即用,但您也可以定义自己的格式。默认情况下,当选定的OutputFormat
转义时,您可以像${foo?no_esc}
一样明确防止转义。
有多种方法可以将模板与您想要的OutputFormat
相关联。对于HTML和XML转义,建议的方法是将recognize_standard_file_extensions
配置设置设置为true
,然后使用HTML的ftlh
文件扩展名和XML模板的ftlx
文件扩展名。您还可以使用OutputFormat
设置,根据任意模板名称(模板路径)模式将template_configurers
- 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
答案 2 :(得分:2)
有一个解决方案,虽然它并非完全无足轻重。您可以创建一个包装其他模板加载器的特殊TemplateLoader,并将&lt; #escape x注入x?html&gt;在模板源文本的序言中,并添加为它的结尾。
明显的缺点: - 第一行中的列号将被丢弃 - 如果您的模板以&lt; #ftl&gt;开头声明,你需要插入&lt; #excape&gt;在它之后。
答案 3 :(得分:2)
如果您使用&lt; #include parse = false ... /&gt;,链接中建议的TemplateLoaders需要稍微调整一下。在模板中包含例如HTML。
此外,您需要复制spring.ftl并使用您自己的副本与&lt; #ftl ..&gt;如汤姆所说,最先删除指令。
以下效果很好,虽然有点粗糙(使用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);
}
}
答案 4 :(得分:1)
您实际上并不需要WrappingReader来添加转义。您可以在任何TemplateLoader周围创建一个装饰器,在模板中读入一个String,在escapes中包装模板文本,然后返回一个读取结果String的StringReader。要了解这是如何完成的,请查看here。我发现的唯一问题是,如果你使用这种方法并从类路径中包含spring.ftl宏,它们会爆炸,因为它们有一个&lt; #ftl&gt;在最顶层的宣言。但是,您可以简单地将spring.ftl复制到模板路径中并删除声明(以及所有转义指令,因为默认情况下您将转义)。