Устранение по умолчанию в Freemarker
В шаблонах Freemarker мы можем использовать директиву escape для автоматического применения экранирования ко всем интерполяциям внутри включенного блока:
<#escape x as x?html>
<#-- name is escaped as html -->
Hallo, ${name}
</#escape>
Есть ли способ программно достичь аналогичного эффекта, определяя выпадение по умолчанию, применяемое ко всем интерполяциям в шаблоне, включая те, которые выходят за пределы управляющих директив?
Спасибо.
Ответы
Ответ 1
Чтобы уточнить ответ Аттилы: вы можете использовать класс этот, а затем обернуть загрузчик шаблонов следующим образом:
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
Начиная с 2.3.24, каждый шаблон имеет связанный объект freemarker.core.OutputFormat
, который указывает, будет ли и как ${...}
(и #{...}
) сбежать. OuputFormat
для HTML, XML и RTF предоставляются из коробки, но вы также можете определить свои собственные форматы. Если выбранный 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
Ответ 3
Существует решение, хотя оно не совсем тривиально. Вы можете создать специальный TemplateLoader, который обертывает другие загрузчики шаблонов, и вводит < #escape x как x? Html > в прологе исходного текста шаблона и добавляет его в качестве эпилога.
Очевидные недостатки:
- номера столбцов в первой строке будут сброшены
- если ваш шаблон начинается с объявления < #ftl > , вам нужно вставить < #escape > после него.
Ответ 4
Рекомендуемые TemplateLoaders в ссылках нуждаются в небольшой настройке, если вы используете < #include parse = false.../" > , чтобы включить, например, HTML в свои шаблоны.
Кроме того, вам нужно скопировать spring.ftl и использовать свою собственную копию с директивой < #ftl.. > сверху, как сказал Том.
Следующее работает хорошо, хотя немного грубо (используя 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);
}
}
Ответ 5
Вам действительно не нужен WrappingReader для добавления экранов. Вы можете просто создать декоратор вокруг любого TemplateLoader, прочитать в шаблоне в String, обернуть текст шаблона в escapes и затем вернуть StringReader, который читает полученную String. Чтобы увидеть, как это делается, посмотрите здесь. Единственное, что я нашел, это то, что если вы используете этот подход и включаете макросы spring.ftl из пути к классам, они взорвутся, так как они имеют объявление < #ftl > на самом верху. Однако вы можете просто скопировать spring.ftl в свой шаблон и удалить декларацию (и все директивы экранирования, поскольку по умолчанию вы будете экранировать).