Thymeleaf + Spring: Как сохранить разрыв строки?

Я использую механизм шаблонов Thymeleaf с spring, и я хотел бы отображать текст, хранящийся в многострочном текстовом поле.

В моей базе данных многострочная строка хранится с "\n" следующим образом: "Test1\nTest2\n...."

С th: текст у меня есть: "Test1 Test2" без разрыва строки.

Как я могу отобразить разрыв строки с помощью Thymeleaf и не вручную "\n" заменить на < br/" > , а затем избегать использования th: utext (эта открытая форма для xss-инъекции)?

Спасибо!

Ответы

Ответ 1

У вас есть два варианта:

  • Используйте th: utext - простая настройка, но труднее читать и запоминать
  • Создание настраиваемого процессора и диалекта - более сложная настройка, но более легкая, более читаемая в будущем.

Вариант 1:

Вы можете использовать th: utext, если вы избежите текста, используя метод утилиты выражения #strings.escapeXml( text ), чтобы предотвратить инъекцию XSS и нежелательное форматирование - http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#strings

Чтобы сделать эту платформу независимой, вы можете использовать T(java.lang.System).getProperty('line.separator') для захвата разделителя строк.

Используя существующие утилиты выражения Thymeleaf, это работает:

<p th:utext="${#strings.replace( #strings.escapeXml( text ),T(java.lang.System).getProperty('line.separator'),'&lt;br /&gt;')}" ></p>

Вариант 2:

После завершения установки все, что вам нужно сделать, чтобы выполнить вывод экранированной строки с сохраненными разрывами строк:

<p david:lstext="${ text }"></p>

Основной частью работы является процессор. Следующий код выполнит трюк:

package com.davidjanney.foo.thymeleaf.processors 

import java.util.Collections;
import java.util.List;

import org.thymeleaf.Arguments;
import org.thymeleaf.Configuration;
import org.thymeleaf.dom.Element;
import org.thymeleaf.dom.Node;
import org.thymeleaf.dom.Text;
import org.thymeleaf.processor.attr.AbstractChildrenModifierAttrProcessor;
import org.thymeleaf.standard.expression.IStandardExpression;
import org.thymeleaf.standard.expression.IStandardExpressionParser;
import org.thymeleaf.standard.expression.StandardExpressions;
import org.unbescape.html.HtmlEscape;

public class HtmlEscapedWithLineSeparatorsProcessor extends
        AbstractChildrenModifierAttrProcessor{

    public HtmlEscapedWithLineSeparatorsProcessor(){
        //only executes this processor for the attribute 'lstext'
        super("lstext");
    }

    protected String getText( final Arguments arguments, final Element element,
            final String attributeName) {

        final Configuration configuration = arguments.getConfiguration();

        final IStandardExpressionParser parser =
            StandardExpressions.getExpressionParser(configuration);

        final String attributeValue = element.getAttributeValue(attributeName);

        final IStandardExpression expression =
            parser.parseExpression(configuration, arguments, attributeValue);

        final String value = (String) expression.execute(configuration, arguments);

        //return the escaped text with the line separator replaced with <br />
        return HtmlEscape.escapeHtml4Xml( value ).replace( System.getProperty("line.separator"), "<br />" );


    }



    @Override
    protected final List<Node> getModifiedChildren(
            final Arguments arguments, final Element element, final String attributeName) {

        final String text = getText(arguments, element, attributeName);
        //Create new text node signifying that content is already escaped.
        final Text newNode = new Text(text == null? "" : text, null, null, true);
        // Setting this allows avoiding text inliners processing already generated text,
        // which in turn avoids code injection.
        newNode.setProcessable( false );

        return Collections.singletonList((Node)newNode);


    }

    @Override
    public int getPrecedence() {
        // A value of 10000 is higher than any attribute in the SpringStandard dialect. So this attribute will execute after all other attributes from that dialect, if in the same tag.
        return 11400;
    }


}

Теперь, когда у вас есть процессор, для добавления процессора требуется специальный диалект.

package com.davidjanney.foo.thymeleaf.dialects;

import java.util.HashSet;
import java.util.Set;

import org.thymeleaf.dialect.AbstractDialect;
import org.thymeleaf.processor.IProcessor;

import com.davidjanney.foo.thymeleaf.processors.HtmlEscapedWithLineSeparatorsProcessor;

public class DavidDialect extends AbstractDialect{

    public DavidDialect(){
        super();
    }

    //This is what all the dialect attributes/tags will start with. So like.. david:lstext="Hi David!<br />This is so much easier..."
    public String getPrefix(){
        return "david";
    }

    //The processors.
    @Override
    public Set<IProcessor> getProcessors(){
        final Set<IProcessor> processors = new HashSet<IProcessor>();
        processors.add( new HtmlEscapedWithLineSeparatorsProcessor() );
        return processors;
    }

}

Теперь вам нужно добавить его в конфигурацию xml или java:

Если вы пишете приложение Spring MVC, вам просто нужно установить его в свойстве дополнительныхDialects механизма шаблонов bean, чтобы он был добавлен к диалоговому диалогу SpringStandard по умолчанию:

    <bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
  <property name="templateResolver" ref="templateResolver" />
  <property name="additionalDialects">
    <set>
      <bean class="com.davidjanney.foo.thymeleaf.dialects.DavidDialect"/>
    </set>
  </property>
    </bean>

Или, если вы используете Spring и предпочитаете использовать JavaConfig, вы можете создать класс, аннотированный с @Configuration в базовом пакете, который содержит диалект, как управляемый bean:

package com.davidjanney.foo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.davidjanney.foo.thymeleaf.dialects.DavidDialect;

@Configuration
public class TemplatingConfig {

    @Bean
    public DavidDialect davidDialect(){
        return new DavidDialect();
    }
}

Вот еще несколько ссылок на создание пользовательских процессоров и диалектов: http://www.thymeleaf.org/doc/articles/sayhelloextendingthymeleaf5minutes.html, http://www.thymeleaf.org/doc/articles/sayhelloagainextendingthymeleafevenmore5minutes.html и http://www.thymeleaf.org/doc/tutorials/2.1/extendingthymeleaf.html

Ответ 2

В моем случае escapeJava() возвращает значения unicode для кириллических символов, поэтому я могу обернуть все в метод метода unescapeJava() для решения моей проблемы.

<div class="text" th:utext="${#strings.unescapeJava(#strings.replace(#strings.escapeJava(comment.text),'\n','&lt;br /&gt;'))}"></div>

Ответ 3

Возможно, не то, что имел в виду OP, но это работает и предотвращает инъекцию кода:

<p data-th-utext="${#strings.replace(#strings.escapeXml(text),'&#10;','&lt;br&gt;')}"></p>

(Использование Thymeleaf в стиле HTML5)

Ответ 4

Попробуйте это

<p th:utext="${#strings.replace(#strings.escapeJava(description),'\n','&lt;br /&gt;')}" ></p>