Pulog

素の Java プロジェクトで SpEL 式の Thymeleaf を使うまで

素の Java プロジェクトで Thymeleaf を使うのであれば、 org.thymeleaf:thymeleaf をライブラリに追加すれば良い。

Gradle の場合

  dependencies {
+  // https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf
+  implementation group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.12.RELEASE'
  }

ただし、これだと Thymeleaf の式言語が標準の OGNL になってしまうので、どうにか Spring のプロジェクトではないけど、式言語を SpEL (Spring Expression Language) にしたくて、検証してみました。

余談として、Spring Boot で何気なく使用していた Thymeleaf の各種演算子が実は Spring の独自拡張で、Spring を用いたプロジェクトではなく、素の Thymeleaf を使っている案件に入った際に気付かされて Spring 様様だなと痛感した次第。

結論 依存ライブラリ

org.thymeleaf:thymeleaf-spring5org.springframework:spring-context を追加して Thymeleaf の実装をすれば SpEL 式でテンプレートを記述することができました。

Gradle の場合

  dependencies {
+      // https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5
+      implementation group: 'org.thymeleaf', name: 'thymeleaf-spring5', version: '3.0.12.RELEASE'
+      // https://mvnrepository.com/artifact/org.springframework/spring-context
+      implementation group: 'org.springframework', name: 'spring-context', version: '5.3.9'
  }

実装例

実際に Gradle で素の Java プロジェクトを作成した後、SpEL 式な Thymeleaf を使う実装を備忘録程度に残しておきます。

Main クラス

src/main/java/Main.java

import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

public class Main {
    public static void main(String[] args) {

        // configure template file resolver
        var resolver = new ClassLoaderTemplateResolver();
        resolver.setTemplateMode(TemplateMode.HTML);
        resolver.setPrefix("template/");
        resolver.setSuffix(".html");

        // init template engine
        var templateEngine = new SpringTemplateEngine();
        templateEngine.setEnableSpringELCompiler(true);
        templateEngine.setTemplateResolver(resolver);

        var result = templateEngine.process("index", new Context());
        System.out.println(result);
    }
}

src/resouces/index.html のテンプレートファイルの処理結果を sysout するシンプルな処理になっています。

org.thymeleaf.spring5.SpringTemplateEngine を使用しているのが点が素の Thymeleaf のライブラリを使用する場合との差分になります。

setEnableSpringELCompiler(true); は以下のドキュメントを見ると、高速化するよとだけ書いていたのでとりあえず記載していますが、流石に今回のレベルの処理だと体感速度は変わらなかったです。

Tutorial: Thymeleaf + Spring

テンプレートファイル

src/main/resouces/index.html

<!doctype html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
    <title>Document</title>
    <h1 th:text="'Hello World.'"
        th:data-hoge="${ 'example' }"></h1>
    <ul>
        <li th:each="item : ${ nullable ?: {} }"></li>
    </ul>
</html>

Main クラスでは nullable というコンテキストを定義していないので null となり、Thymeleaf の処理を走らせようとすると NullPointerException が本来は発生してしまうのですが、OGNL 式にはなく SpEL 式には存在するエルビスオペレーター (Elvis Operator) を使用して例外エラーにならないように記述しています。

もし、式言語が OGNL でこの例外エラーを回避する場合は以下のような処理になり、やや冗長さを感じてしまいます。

    <ul>
        <li th:each="item : ${ nullable } ? ${ nullable } : ${ {} }"></li>
    </ul>

他にも、オプショナルチェイニング演算子 (Safe Navigation operator) なども使えるので、一度 SpEL 式で調べてみると良いかもしれないです。

Main クラス実行結果

例外エラーも発生せずに <li> 要素が出力されていないことが確認できます。

<!doctype html>
<html lang="ja">
    <title>Document</title>
    <h1 data-hoge="example">Hello World.</h1>
    <ul>
        
    </ul>
</html>

以上、できるだけ最低限のライブラリだけで SpEL 式で Thymeleaf を実行してみました。
本当は Spring MVC とか Spring Boot 上でやればいいんだけどね……