Java入門 / Web入門

【Java Web入門 #16】Thymeleafの利用(3) | Thymeleafの式構文

2025.03.28

一般的に Thymeleaf のテンプレートは式と属性の2つを組み合わせて記述し、属性の値として式を利用します。これらは JSP におけるカスタムタグとEL式と似たような関係です。他に Thymeleaf では特殊なコメント(コメントアウト)を利用することもできます。当記事では、 Thymeleaf で扱う式の種類や、コメントアウトの書式などについて説明します。

◆Java Web入門の過去記事はこちら
◆Java入門 記事一覧はこちら

Thymeleafの式と属性

Thymeleafの基本的な構成

Thymeleaf のテンプレートは式と属性の2つを組み合わせて記述します。式は ${ ... } や #{ ... } のように括弧で囲んで式としての処理を行い、属性は th:text 、th:if などHTMLタグ内に記述することで対象のタグ、またはその子要素のタグに対して処理を行います。

例えば以下のサンプルコードでは、<span> タグの内部の文字列を式の結果に置き換えたり、式の結果に応じて<div>の出力を切り替えたりしています。

<!-- 内部のテキストをパラメータ'a'の値に置き換え -->
<span th:text="${param.a}">ここにパラメーター'a'の値を出力</span>

<!-- パラメーター'b'の値に応じたdivを出力 -->
<div th:if="${param.b eq null or param.b eq ''}">
	<p >パラメーター'b'の値が指定されていません。</p>
</div>
<div th:if="${param.b ne null and param.b ne ''}">
	<p>パラメーター'b'の値は<span th:text="${param.b}"></span>です。</p>
</div>

Thymeleaf で利用される式言語

通常 Thymeleaf の式言語には OGNL(Object Graph Navigation Language)と呼ばれる、Javaに似た式言語が利用されますが、Spring MVC や Spring Boot 上の Thymeleaf は SpEL(Spring Expression Language)と呼ばれる Spring フレームワーク向けの式言語で動作します。これらの式言語はほぼ同じ動作を行いますが、一部のキーワードや動作など異なる点もあります。

当記事では Spring Boot を利用した Java の Webアプリケーション上での利用を想定しているため、以降の説明については SpEL での動作が前提となりますのでご注意ください。(OGNL の利用が前提である公式のチュートリアルとは一部異なる箇所があります)

テンプレート内で利用できるコメント

Thymeleaf のテンプレート上では、3種類のコメントを利用することができます。これらのコメントは、Thymeleaf のテンプレートとしてWebアプリケーション上で表示させた場合に、動作や出力される内容が異なります。

通常のHTMLコメント

Thymeleaf のテンプレートでは、通常のHTMLコメントが利用できます。

書式:
 <!-- コメント -->

静的HTMLとして表示HTMLコメントとして表示
Thymeleaf での動作HTMLコメントとして表示

HTMLコメントを利用した場合、テンプレートをHTMLファイルとして表示する際にはコメントとして表示されますが、テンプレートとして利用した場合はコメント内の Thymeleaf の属性や式などの処理は実行されてしまうことに注意が必要です。

結果として、Webアプリケーション上で動作した際には、 Thymeleaf で 処理された結果が、生成されるHTML上にコメントとして出力されます。

Thymeleaf パーサーレベルのコメント

Thymeleaf パーサーレベルのコメント

書式:
 <!--/* コメント */-->

静的HTMLとして表示HTMLコメントとして表示
Thymeleaf での動作(何も表示されない)

Thymeleaf パーサーレベルのコメントでは、コメント内に記述された Thymeleaf の属性や式の処理は行われません。また、Webアプリケーション上で動作した際は生成されるHTML上にもコメント自体が残りません。

HTML上に出力したいコメントは通常のHTMLコメント、Thymeleaf に処理をさせたくない、または生成されるHTML上には出力させたくない場合は パーサーレベルのコメント、と使い分けることが必要でになります。

プロトタイプのみのコメント

書式:
 <!--/*/ コメント /*/-->

静的HTMLとして表示HTMLコメントとして表示
Thymeleaf での動作通常のHTMLコードおよび Thymeleaf の項目として動作

プロトタイプのみのコメントは特殊なコメントで、テンプレートを静的なHTMLとして開いた場合にはコメントとして表示されますが、Webアプリケーション上で動作した際は通常のHTMLコードと Thymeleaf の属性・式として処理されます。(すなわち、Thymeleaf の動作時はコメント内部の記述が通常のコードとみなされる)

実際のWebアプリケーション上では Thymeleaf のテンプレートとして動作させたいが、モックアップの作成時にはコメントアウトしておきたいような項目がある場合などに、プロトタイプのみのコメントが利用できます。

Thymeleafの式構文

${ ... } 変数式

Thymeleaf のテンプレートでは、式の中でリクエストパラメーターやコントローラーから受け取った変数を扱う場合、変数式を利用します。 ${ ... } 変数式は、Thymeleaf で最も基本となる式の構文です。

前回の記事のように、Spring Boot の Controller を準備して、Thymeleaf に引き渡す変数を準備します。以下のサンプルでは、Model を通じて 文字列「productName」および「price」と配列「colors」、session の「details」属性として 商品の詳細情報 HashMap のインスタンスを保持しています。

コントローラークラス(ProductController.java)

Java
package com.example.demo.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import jakarta.servlet.http.HttpSession;

@Controller
public class ProductController {

  private HttpSession session;

  public ProductController(HttpSession session) {
    this.session = session;
  }
	
	@GetMapping("/prod")
	public String prod(Model model) {
		
		model.addAttribute("productName", "iPhone 16");
		model.addAttribute("price", 124800);
		
		String[] colors = {"ウルトラマリン", "ティール", "ピンク", "ホワイト", "ブラック"};
		model.addAttribute("colors", colors);
		
		Map<String, Object> details = new HashMap<>();
		details.put("size", "6.1");
		details.put("height", "147.6mm");
		details.put("width", "71.6mm");
		session.setAttribute("details", details);
		
		return "product";
	}
}


次に、コントローラークラスで設定した変数を表示するためのテンプレートを準備します。

テンプレート(product.html)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>Product Detail Page</title>
  </head>
  <body>
	<p>製品名:[[ ${productName} ]]</p>
	<p>価格:[[ ${price} ]]円</p>
	<p>(内消費税):[[ ${price * 10 / 110} ]] 円</p>
	<p>詳細:</p>
	<div style="padding: 0 20px;">
		<p>色:[[ ${colors[0]} ]]</p>
		<p>ディスプレイ:[[ ${session.details.size} ]] インチ</p>
		<p>サイズ(縦 x 横):[[ ${session.details.height + ' x ' + session.details.width} ]]</p>
	</div>
  </body>
</html>


実行結果:


パラメーターへのアクセス以外にも、変数式ではプロパティへのアクセスやメソッドの呼び出し、session や application スコープに対する属性の取得を行うことができます。また、複数個の変数を利用したり、演算子やユーティリティオブジェクトを用いた処理を行うことも可能です。

変数式の中では、大括弧 [ ] を利用することで、名前を指定してプロパティへのアクセス、配列やコレクションに対するインデックスの指定、マップからキー名での値の取得を行うこともできます。

*{ ... } 選択変数式

変数式 ${ ... } 内では変数を検出する範囲(参照先)はコンテキスト全体であったのに対し、選択変数式 *{ ... } では変数の参照先が、上位要素において th:object 属性で選択したオブジェクトとなります。

オブジェクトを選択していない場合は参照先はコンテキスト全体となるため、変数式 ${ ... } と同じ動作となります。

以下のサンプルコードでは、全て同じ項目(リクエストパラメーター "name")を出力していますが、上から3番目の選択変数式では、親div で選択したオブジェクト ${param} を起点として *{name} とだけ記述することができます。

<!-- 選択オブジェクトなし -->
<div>
  [[${param.name}]] <!-- 通常の変数式 -->
</div>
<div>
  [[*{param.name}]] <!-- 選択オブジェクトがないため通常の変数式と同じ動作となる -->
</div>

<!-- 選択オブジェクトに${param}を設定 -->
<div th:object="${param}"> 
  <div>
    [[*{name}]]  <!-- 選択オブジェクトのnameプロパティ -->
  </div>
  <div>
    [[${#object.name}]] <!-- 選択オブジェクト(= #object)のnameプロパティ -->
  </div>
  <div>
    [[${param.name}]] <!-- 選択オブジェクトを利用せず、通常の変数式でアクセス -->
  </div>
</div>

<!-- 選択オブジェクトに${param.name}を設定 -->
<div th:object="${param.name}">
  [[${#object}]] <!-- 選択オブジェクトを直接出力 -->
</div>


セッション上に保持したBeanを利用する場合など、1つのオブジェクトに対して繰り返し処理や出力を行いたい場合には、選択変数式を利用することでシンプルな記述が実現できます。

参考:4.3 選択に対する式(アスタリスク構文)- Thymeleaf チュートリアル

#{ ... } メッセージ式

メッセージ式 #{ ... } では、リソースのメッセージ処理を行うことができます。

メッセージリソースを利用するために、/src/main/resources 配下に プロパティファイル messages.properties(※)を準備します。
(プロパティファイルの編集については、以前の記事(【Java Web入門 #11】標準タグライブラリ(JSTL)の利用(3))を参照)

msg01=こんにちは。
msg02=こんにちは、{0}さん。


次に、Spring Boot の設定ファイル application.properties(※)に、以下の定義を追加します。

spring.messages.basename=messages
spring.messages.encoding=UTF-8

(※ YAMLファイルを利用している場合はmessages.yml/application.yml に定義)

テンプレート上でメッセージを利用する場合は、以下のように記述します。置換パラメーターへ埋め込む値には変数式も利用できます。

<p>[[#{msg01}]]</p>
<p>[[#{msg02('ゲスト')}]]</p>
<p>[[#{msg02(${param.name})}]]</p>


以下のサンプルコードでは、定義したメッセージにパラメーター文字列を埋め込んで画面に表示しています。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>Message Sample Page</title>
  </head>
  <body>
	<p>[[#{msg02(${param.name})}]]</p>
  </body>
</html>


実行結果:

@{ ... } リンクURL式

リンクURL式 @{ ... } では、HTMLのアンカータグ(<a>タグ)の href 属性に対して設定する、URL の文字列を生成するために利用します。また、リンクURL式を利用してGETパラメーターを設定することで、クエリーストリングのパラメーターを必要に応じてURLエンコードすることが可能です。

以下のサンプルコードでは、href 属性 に「name」「lang」の2つのパラメーターを設定したURL文字列を生成して、<a>タグの href 属性の値を置き換えます。

<a href="sample.html" 
	 th:href="@{/sample(name=${param.name},lang='日本語')}">リンク</a>


実行結果:

~{ ... } フラグメント式

フラグメント式 ~{ ... } は、ht:insert 属性または th:replace 属性の値として利用し、定義されたフラグメントを埋め込むことが可能です。

フラグメントは th:fragment 属性で定義され、テンプレートファイルをまたいで利用することが可能です。例えば、ヘッダー、フッターやメニューバーなどを共通的なフラグメントとして準備して各画面で利用することなどができます。

以下のサンプルコードでは、frg.html にフラグメント「header」を定義して、sample.html ではフラグメントを利用して画面に表示しています。

フラグメントの定義(frg.html)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <body>
	<div th:fragment="header">
		<div style="width:100%; background-color: aquamarine; text-align: center;">
			[Thymeleaf sample page]
		</div>
	</div>
  </body>
</html>


フラグメントの利用(sample.html)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>Sample Page</title>
  </head>
  <body>
    <!-- フラグメント -->
	  <div th:replace="~{frg :: header}"></div>
  </body>
</html>


Spring Boot アプリケーション上で sample.html にアクセスすると、<div th:fragment="header"> で定義したフラグメントが、sample.html に埋め込まれて出力されているのがわかります。

式のインライン処理

[[ ... ]] インライン式による出力

Thymeleaf の属性である th:text では、タグのボディ部のテキストを差し替えて出力しますが、インライン式を利用することで、HTML上の任意の位置に文字列を出力することが可能です。

通常のインライン出力は大括弧を重ねて記述します。出力対象にXML特殊文字(「<」「>」「 " 」「 ' 」「&」の5文字)が含まれていた場合は、エスケープして出力されます。

書式:
 [[ expression ]]

以下のサンプルコードでは、どちらも名前の部分にリクエストパラメーター(name)の値を出力しますが、インライン式を利用することでシンプルに埋め込むことができます。

<!-- インライン式を利用 -->
<p>こんにちは、[[ ${param.name} ]]さん。</p>

<!-- th:text 属性を利用 -->
<p>こんにちは、<span th:text="${param.name}">名無し</span>さん。</p>


ただしインライン式を利用する場合、テンプレートファイルをHTMLとして表示した際にインライン式がそのまま表示されるため、モックアップの作成などには向かない場合があります。どちらで出力を行うかは用途に応じて使い分ける必要があることに注意してください。

上記のサンプルコードを含むテンプレートファイルを、静的HTMLとしてブラウザ表示した場合の動作は以下の通りです。

利用方法静的HTMLとしての表示ブラウザ上の表示(<p>~</p>の部分)
インライン式インライン式の文字列をそのまま表示こんにちは、[[ ${param.name} ]]さん。 
th:text 属性th:text 属性を無視して表示こんにちは、名無しさん。

[( ... )] XMLエスケープをしない出力

Thymeleaf では、大括弧の中に小括弧を記述した場合もインライン式として扱われます。

書式:
 [( expression )]

但しこの場合、大括弧2個のインライン式と異なり、XML特殊文字(「<」「>」「 " 」「 ' 」「&」の5文字)をエスケープせずに直接出力します。つまり、出力する文字列がHTML文字列であった場合、HTMLのオブジェクトとして出力されます。



いかがでしたでしょうか。Thymeleaf の式構文の種類はそれほど多くありませんが、これらの式構文やコメントを使い分けることは、シンプルで保守性の高いテンプレートの作成に役立ちます。次回の記事では、これらの式の使用例を交えながら、各機能を利用するためのThymeleaf の属性について説明します。

株式会社GSI 採用サイト

新しいこと、始めよう

あなたとともに歩を進めるWEBメディア

広告

広告