Устранение по умолчанию в 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 в свой шаблон и удалить декларацию (и все директивы экранирования, поскольку по умолчанию вы будете экранировать).