ThymeleafをController以外の場所で使う方法

こんにちは。 エキサイト株式会社の三浦です。

JavaでSpring Bootを使っている時にHTMLを扱いたい場合、Thymeleafというテンプレートエンジンを使うことが多いのではないでしょうか。 多くの場合はControllerから返却するときに自動でテンプレートファイルを紐付ける方法で事足りると思いますが、まれにController以外の場所で明示的に呼び出して使いたい場合もあります。

今回は、その方法を紹介します。

Thymeleafとは

Thymeleafは、Java用のテンプレートエンジンです。

Thymeleafは、ウェブとスタンドアローンどちらの環境でも利用できる、モダンなサーバーサイドJavaテンプレートエンジンです。HTML、XMLJavaScriptCSS、さらにプレーンテキストも処理することができます。

例えばHTMLを扱いたい場合、変数部分以外をテンプレートファイルとして最初から作っておき、最後に変数部分をコード側から注入することで、コード内で文字列からHTMLを組み立てるよりも圧倒的に見通しの良いコードにすることができます。

<div xmlns:th="http://www.thymeleaf.org">
    <span th:text="${title}"></span>
    
    <span th:text="${story}"></span>
</div>

通常使う場合は、Controllerからの返却時に自動的にテンプレートファイルを紐付け、最終的にHTMLをレスポンスとして返す方法を取りますが、これだと例えばコード内で一部のHTMLのみを組み立てたい、ということができません。 ですが実は、一部の設定を変更することで、明示的にテンプレートファイルをController以外の場所から呼び出して使用することができるようになります。

明示的に呼び出す方法

まずは、テンプレートエンジンの設定をカスタマイズしてBean化します。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

@Configuration
public class SpringTemplateEngineConfig {
    /**
     * SpringTemplateのBean化
     * @return 設定済みSpringTemplate
     */
    @Bean
    public SpringTemplateEngine springTemplateEngine() {
        var resolver = new ClassLoaderTemplateResolver();

        // HTMLとして使用
        resolver.setTemplateMode(TemplateMode.HTML);

        // resources配下で、どんなプレフィックスのファイルを使うか
        resolver.setPrefix("templates/");
        // resources配下で、どんなサフィックスのファイルを使うか
        resolver.setSuffix(".html");

        // 文字列エンコード
        resolver.setCharacterEncoding("UTF-8");

        // キャッシュするかどうか
        resolver.setCacheable(true);

        var engine = new SpringTemplateEngine();
        engine.setTemplateResolver(resolver);

        return engine;
    }
}

設定できたら、使用します。

resources/templates/sample.html に以下を配置

<div xmlns:th="http://www.thymeleaf.org">
    <span th:text="${title}"></span>
    
    <span th:text="${story}"></span>
</div>
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;

@Component
@RequiredArgsConstructor
public class SampleImpl implements Sample {
    private final SpringTemplateEngine springTemplateEngine;

    @Override
    public String sample() {
        var context = new Context();
        context.setVariable("title", "サンプルタイトル");
        context.setVariable("story", "サンプル本文");
        String html =  springTemplateEngine.process("sample", context);

        return html;
    }
}

これで、 sample() メソッドを実行することで、指定のHTMLを文字列で取得することができるようになります。

最後に

上記のサンプル程度なら文字列から組み立てても大して問題はないでしょうが、これが複雑になっていくに連れテンプレートファイルで分けることで見通しが相当良くなっていきます。 ぜひ使ってみていただけると幸いです。

なおこの方法を使うと、今度はControllerでの自動紐付けができなくなるそうなので、両方で使いたい場合はController用と明示的呼び出し用の2つ分を設定する必要があることを注意してください。