i-Vinci TechBlog
株式会社i-Vinciの技術ブログ

はじめてのThymeleaf

こんにちは。i-Vinci D.Sです。

最近、初めてSpringboot+Thymeleafを用いた開発に携わる機会がありました。
そもそもフロント側の開発経験が浅い私からしたら、Thymeleafとは?くらいのレベルでしたが、学習を重ねて徐々に理解度が深まってきました。
今回はThymeleafの学習をこれから始める方に向けてThymeleafで個人的に躓いた点を記事にしてみました。

1. Thymeleafとは

ThymeleafはJava用のテンプレートエンジンでSpringbootでの使用が推奨されています。
HTMLの文法に則ってテンプレートを書くことができる仕様となっており、テンプレート自体をブラウザで表示することが可能であるというメリットがあります。
私はJSPでの開発が多かったこともあり、とても便利だと感じました。

使用するにはビルドツールに依存関係を追加する必要があります。

  • build.gradle(=gradleを使う場合)
    dependencies {
      implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
      implementation 'org.springframework.boot:spring-boot-starter-web'
    }
    
  • pom.xml(=Mavenを使う場合)
    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf-spring4</artifactId>
      <version>3.0.0.RELEASE</version>
    </dependency>
    

あとはhtmlファイルに<html xmlns:th="http://www.thymeleaf.org">と記述すれば、以降HTMLタグの中にThymeleafプロセッサーを使えるようになり、
Thymeleafプロセッサーが有効になることでThymeleaf独自の文法をテンプレートへ記述することで処理が行われます。
またThymeleafには独自の文法を記述する為にStandardDialectというライブラリが備わっており、これによりタグ(要素や属性)や式が使用できます。

・参考:Tutorial: Using Thymeleaf (ja)

2. 躓きやすいポイント

ローカル変数への値の再代入は出来ない

  • 事象
    以下の例文では、th:withでローカル変数を定義し値を代入し、同スコープ内で値を再度代入しようとしています。

    <!-- 変数prodへの代入1回目 -->
    <th:block th:with="prod='foo'">
    <th:block th:if=${条件式}>
    <!-- 変数prodへの代入2回目 -->
      <th:block th:with="prod='bar'">
        <p th:text="${prod}"></p>
      </th:block>
    </th:block>
    </th:block>
    

    <p th:text="${prod}"></p><p>foo</p>と評価されて欲しいところですが、実際には<p>bar</p>となってしまいます。実はThymeleafでは同スコープ内の変数の再代入が行えません。
    では、同スコープ内で変数を更新できないとなると、どのようにすればよいのでしょうか。
    ※別スコープであれば再度変数の設定は可能です。

  • 対処法
    上述のとおり同スコープ内の変数への再代入ができないことがわかりました。
    本仕様はチュートリアルに記載がないので、実装過程で躓いて初めて気づくポイントだと思います。
    もし、条件に応じて変数を変更したい場合には、th:withをネストせずに、三項演算子を用いることで実現することができます。

    <!-- 条件判定してprodに値を代入 -->
    <th:block th:with="prod=(${条件式} ? 'foo' : 'bar')">
    <p th:text="${prod}"></p>
    </th:block>
    

    三項演算子を用いれば、with変数を定義する際に代入する値をコントロールすることができるので、再代入の代わりとして扱うことができます。

Thymeleafにおける処理の順序性

  • 事象
    th:text(テキストを出力する処理)で、処理順を意識せずコーディングを行うと、出力したいタグが表示されないという事象が発生します。
    これはThymeleafの処理の順序性を意識していないと嵌りやすいポイントかと思います。

    <p th:text="hoge">
    <span class="fuga">fugafuga</span>
    </p>
    

    上記のように<p>タグ内でth:text<span>タグを定義すると、以下のように評価されてしまいます。

    <p>
      hoge <!-- spanタグがどこかに消えた。。。 -->
    </p>

    この記述では先に<p>タグ内に定義されているth:textの表示が優先されてしまう為、<span>タグが表示されなくなってしまいます。
    厳密に言うと<span>タグの上にth:textのテキスト文が被ってしまい隠れてしまう形になります。

  • 対処法
    両方を出力する方法としては以下の記述で対処できます。

    <p>
      <th:block th:text="hoge"></th:block>
      <span class="fuga">fugafuga</span>
    </p>

    評価後

    <p>
      hoge
      <span class="fuga">fugafuga</span>
    </p>

    th:textは自身が含まれるタグで挟まれた箇所を属性値に置換する仕様となっています。ですので、対処法のようにth:text<th:block>タグの属性として記述することで<p>タグの中が置き換わることを防ぐことができます。

    3. 最後に

    今回はThymeleafをこれから学習する方に向けて躓きやすいポイントについて書いてみました。
    特にローカル変数への再代入についてはチュートリアルには記載されていない内容なので、
    この問題に直面した時は解決するのに少し時間がかかりました。
    他にもThymeleafについて共有できる事項があれば、私の備忘も兼ねて書いてみたいと思います。