web-dev-qa-db-fra.com

Thymeleaf + Spring: Comment garder le saut de ligne?

J'utilise le moteur de template Thymeleaf avec spring et j'aimerais afficher le texte stocké dans une zone de texte multiligne.

Dans ma base de données, les chaînes multilignes sont stockées avec "\ n" comme ceci: "Test1\nTest2\n ...."

Avec th: le texte que j'ai: "Test1 Test2" sans saut de ligne.

Comment afficher le saut de ligne avec Thymeleaf et éviter de remplacer "\ n" manuellement par <br />, puis d’éviter d’utiliser th: utext (cette forme ouverte pour xss injection)?

Merci !

18
Daividh

Deux de vos options: 

  1. Utilisez th: utext - option de configuration facile, mais plus difficile à lire et à mémoriser
  2. Créez un processeur et un dialecte personnalisés - configuration plus complexe, mais utilisation future plus facile et plus lisible.

Option 1:

Vous pouvez utiliser th: utext si vous échappez le texte à l'aide de la méthode d'utilitaire d'expression #strings.escapeXml( text ) pour empêcher toute injection XSS et toute mise en forme non souhaitée - http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#strings

Pour rendre cette plate-forme indépendante, vous pouvez utiliser T(Java.lang.System).getProperty('line.separator') pour saisir le séparateur de ligne. 

En utilisant les utilitaires d’expression Thymeleaf existants, ceci fonctionne:

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

Option 2:

L'API pour cela est maintenant différent en 3 (j'ai écrit ce tutoriel pour 2.1) Espérons que vous puissiez combiner la logique ci-dessous avec leur tutoriel officiel. Un jour, j'aurai peut-être une minute pour mettre cela complètement à jour. Mais pour l'instant: Voici le didacticiel officiel de Thymeleaf pour créer votre propre dialecte.

Une fois la configuration terminée, tout ce que vous aurez à faire pour obtenir une sortie de texte échappée avec des sauts de ligne préservés:

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

La pièce principale faisant le travail est le processeur. Le code suivant fera l'affaire:

package com.foo.bar.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;
    }


}

Maintenant que vous avez le processeur, vous avez besoin d'un dialecte personnalisé pour y ajouter le processeur.

package com.foo.bar.thymeleaf.dialects;

import Java.util.HashSet;
import Java.util.Set;

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

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

public class FooDialect extends AbstractDialect{

    public FooDialect(){
        super();
    }

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

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

}

Maintenant, vous devez l'ajouter à votre configuration XML ou Java:

Si vous écrivez une application Spring MVC, il vous suffit de la définir dans la propriété additionalDialects du bean Template Engine, de sorte qu'elle soit ajoutée au dialecte SpringStandard par défaut:

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

Ou, si vous utilisez Spring et préférez utiliser JavaConfig, vous pouvez créer une classe annotée avec @Configuration dans votre package de base contenant le dialecte sous forme de bean géré:

package com.foo.bar;

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

import com.foo.bar.thymeleaf.dialects.FooDialect;

@Configuration
public class TemplatingConfig {

    @Bean
    public FooDialect fooDialect(){
        return new FooDialect();
    }
}

Voici d'autres références sur la création de processeurs et de dialectes personnalisés: http://www.thymeleaf.org/doc/articles/sayhelloextendingthymeleaf5minutes.html , http://www.thymeleaf.org/doc/articles/ sayhelloagainextendingthymeleafevenmore5minutes.html et http://www.thymeleaf.org/doc/tutorials/2.1/extendingthymeleaf.html

20
David Roberts

Dans mon cas, escapeJava() renvoie des valeurs unicode pour les symboles cyrilliques. Je vais donc envelopper toutes les méthodes unescapeJava() pour résoudre mon problème.

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

Peut-être pas ce que le PO avait en tête, mais cela fonctionne et empêche l'injection de code:

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

(Utilisation de Thymeleaf de style HTML5.)

5
holmis83

Essaye ça

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

Vous devez utiliser th: utext et ajouter une ligne de séparation à la chaîne . Mon code est:

StringBuilder message = new StringBuilder();
        message.append("some text");
        message.append("<br>");
        message.append("some text");

<span th:utext="${message}"></span>
0
Stefan Dosković