Thymeleafで改行を含んだ文字列を th:text 等で出力しても、改行は画面に反映されません。
改行コードを<br/>タグへ変換してあげる必要があります。
環境
- Java 1.8
- spring-boot 1.5.6.RELEASE
- Thymeleaf 2.1.5
ポイント
- 改行コード(\r, \n, \r\n)を<br/>に変換する。
- 変換した<br/>タグ以外のhtmlタグはエスケープする。
実装
2通りの方法があるので紹介します。
① View上で実装
既存のThymeleaf構文のみを使用。
事前の設定等はいらないので気軽に使用可能。
<th:block th:if="${sentence}">
<th:block th:each="str, stat : ${sentence.split('\r\n|\r|\n', -1)}">
<th:block th:text="${str}"/>
<br th:if="${!stat.last}"/>
</th:block>
</th:block>
出力したい文字を改行コードで分割して th:each でループ。
中身を th:text で出力しつつ、間に<br/>を挿入しているだけである。
② 独自ダイアレクトを定義
上記の実装は手軽だが、複数個所で使用するとなると煩雑になってしまいます。
そこで独自ダイアレクトを作成してViewから参照できるようにします。
変換処理とテキスト出力するプロセッサ
TextLineProcessor.java
import org.thymeleaf.Arguments;
import org.thymeleaf.Configuration;
import org.thymeleaf.dom.Element;
import org.thymeleaf.processor.attr.AbstractUnescapedTextChildModifierAttrProcessor;
import org.thymeleaf.standard.expression.IStandardExpression;
import org.thymeleaf.standard.expression.IStandardExpressionParser;
import org.thymeleaf.standard.expression.StandardExpressionExecutionContext;
import org.thymeleaf.standard.expression.StandardExpressions;
import org.unbescape.html.HtmlEscape;
/**
* 改行コードをbrタグに変換するプロセッサ
*/
public class TextLineProcessor extends AbstractUnescapedTextChildModifierAttrProcessor {
public static final int ATTR_PRECEDENCE = 1450;
public static final String ATTR_NAME = "textbr";
protected TextLineProcessor() {
super(ATTR_NAME);
}
@Override
public int getPrecedence() {
return ATTR_PRECEDENCE;
}
/**
* 出力する文字列を返す
*
* @param arguments
* @param element
* @param attributeName
* @return
*/
@Override
protected final String getText(
final Arguments arguments, final Element element, final String attributeName) {
String text = getAttributeObjectString(arguments, element, attributeName);
// htmlエスケープ処理
text = HtmlEscape.escapeHtml4Xml(text);
// 改行コードをbrタグへ置換
return text.replaceAll("\r\n|\r|\n", "<br/>");
}
/**
* 属性に指定された変数を文字列として取得する
*
* @param arguments
* @param element
* @param attributeName
* @return
*/
protected String getAttributeObjectString(
final Arguments arguments, final Element element, final String attributeName) {
final String attributeValue = element.getAttributeValue(attributeName);
final Configuration configuration = arguments.getConfiguration();
final IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(configuration);
final IStandardExpression expression = expressionParser.parseExpression(configuration, arguments, attributeValue);
final Object result =
expression.execute(configuration, arguments, StandardExpressionExecutionContext.UNESCAPED_EXPRESSION);
return (result == null ? "" : result.toString());
}
}
th:text と th:utext の処理を参考に実装しました。
簡単に処理を説明すると・・・
1. htmlタグのエスケープ処理
2. 改行コードを<br/>タグへ置換
3. それをエスケープせずに画面出力
ダイアレクトの登録
作成したプロセッサをダイアレクトに登録する。
CustomDialect.java
import org.thymeleaf.dialect.AbstractDialect;
import org.thymeleaf.processor.IProcessor;
import java.util.HashSet;
import java.util.Set;
/**
* 独自定義したダイアレクトを登録する
*/
public class CustomDialect extends AbstractDialect{
static final String DIALECT_PREFIX = "ex";
@Override
public String getPrefix() {
return DIALECT_PREFIX;
}
@Override
public Set<IProcessor> getProcessors() {
final Set<IProcessor> processors = new HashSet<IProcessor>();
processors.add(new TextLineProcessor());
return processors;
}
}
Thymeleaf設定
ThymeleafConfiguration.java
import com.ushidatmhr.thymeleaf.CustomDialect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ThymeleafConfiguration {
@Bean
CustomDialect myDialect() {
return new CustomDialect();
}
}
使い方
<p ex:textbr="${sentence}" />