第5章 Thymeleafの利用

5.5 Thymeleafの色々な使い方

Thymeleafにはもっと色々な使い方が用意されているので、基本的な機能を1つずつ試していってみましょう。その前にまずはベースとなるテンプレートファイルとクラスファイルを作成していきます。

5.5.1 テンプレートファイルの作成

1

「src/main/resources」パッケージの「templates」フォルダ内に「thymeleaf」フォルダを作成

2

1で作成した「thymeleaf」フォルダ内に「howto.html」を作成

3

2で作成した「howto.html」ファイルに以下に示すソースコードを記述する。

■ソースコード
【ファイル名:howto.html】

5.5.2 クラスファイルの作成

1

「jp.co.f1.spring.thymeleaf」パッケージを作成

2

「jp.co.f1.spring.thymeleaf」パッケージに「ThymeleafController.java」の作成とソースコードの記述

作成した「ThymeleafController」クラスファイルに以下に示すソースコードを記述する。

■ソースコード
【ファイル名:ThymeleafController.java】

    package jp.co.f1.spring.thymeleaf;

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GettMapping;
    import org.springframework.web.servlet.ModelAndView;

    @Controller
    public class ThymeleafController {
	  
      // 「/thymeleaf」へアクセスがあった場合
      @GetMapping("/thymeleaf")
      public ModelAndView thymeleaf(ModelAndView mav) {
        // 画面に出力するViewを指定
        mav.setViewName("thymeleaf/howto");
        // ModelとView情報を返す
        return mav;
      }

    }
    

5.5.3 Javaのインスタンスやメソッドもそのまま使える

Thymeleafの基本は、「値を出力する(表示する)」ということです。これは${○○}という形で記述されます。この${}という書き方は「変数式」と呼ばれます。
変数式の中に記述されるのは、「OGNL」(Object-Graph Navigation Language)式という、Javaの値にアクセスするための式言語です。Thymeleafに限らず、各種のライブラリやフレームワークなどで使われています。

OGNLは、Javaの簡易版のような書き方をするので、Javaプログラマであればそれほど難しくはありません。基本的に「Javaで式を書けば、シンプルなものならたいていはOGNLの式になる」と考えてしまっていいでしょう。
既に基本的なOGNLは使っていますが、ここではもう少し違ったサンプルを挙げてみましょう。
先ほど作成したhowto.htmlを開き、<div class=”contents”>タグの部分をこのように書き換えてみてください。

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf

図 5.5 1:Thymeleafの色々な使い方(Javaのインスタンスやメソッドもそのまま使える)

ここでは、th:textに、${new java.util.Date().toString()}というように値を指定しています。変数式には、単に変数や値などを書くだけでなく、このようにインスタンスをnewしたり、メソッドを呼び出したりするOGNLの式を書くこともできるのです。

5.5.4 ユーティリティオブジェクト

変数式は、その名の通り、変数を記述してそのまま出力することができます。この変数は、既に簡単なサンプルで動作を確認したように、まずコントローラーで値を用意しておき、それをテンプレート側に出力する、というのが基本でした。

が、例えばJavaのクラスなどの中には、こうしたテンプレートで頻繁に用いられるクラスもあります。そうしたものを利用する際、常に「コントローラーでこのクラスを変数として用意して…」とやるのはとても面倒ですよね。
そこでThymeleafでは、よく使われるクラスを「#名前」という定数として変数式の中に直接記述して利用できるようにしました。これが「ユーティリティオブジェクト」です。
ユーティリティオブジェクトには、以下のようなものがあります。

これらはクラスの定数ですので、ここから直接クラスメソッドなどを呼び出して利用することができます。ただし、例えば「new #dates」などとやってDateインスタンスを作る、といった使い方はできません。あくまで、「#dates.○○」というように、クラスフィールドやクラスメソッドの呼び出しを行うのに利用するもの、と考えてください。

では、実際にユーティリティオブジェクトを利用した例を挙げておきましょう。これもコントローラー側は特に修正の必要はなく、テンプレート(howto.html)を修正するだけで済みます。

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf


図 5.5 2:Thymeleafの色々な使い方(ユーティリティオブジェクト)

ここでは、日時、整数、テキストといった値を決まった形に整形して表示しています。
順番に見てみましょう。

■日時の整形

#datesは、Dateクラスの定数でした。そのformatメソッドを使い、引数で作成しているDateを決まった形式で表示しています。ここでは、dd/MM/yyyy HH:mmという形でパターンを用意してあります。

■整数の整形

#numbersは、Numberクラスの定数でした。formatIntegerメソッドは、整数を決まった桁数表記にします。第1引数の整数を第2引数の桁表示にして返します。

■テキストの整形

#stringsは、Stringクラスの定数でした。toUpperCaseは、引数のテキストをすべて大文字に変換するメソッドです。

ユーティリティオブジェクトは、このように、値を整形するなどちょっとした処理を変数式内に組み込みたい場合に役立ちます。

5.5.5 パラメータへのアクセス

Webアプリケーションでは、クエリー文字列にパラメータを付けて送信することがよくあります。例えば、「/thymeleaf?id=123」といった形でアクセスして、123の値を受け取って利用する、ということですね。
コントローラーでこうしたパラメータを処理するやり方は既に説明しました。が、コントローラーを通さず、直接テンプレート内でパラメータを利用したいこともあるかも知れません。

このような場合に利用されるのが「param」という変数です。これは、変数式の中で直接利用できる変数です。変数の中からパラメータ名を指定して値を取り出すことができます。例えば${param.id}とすれば、id=○○という形で送られてきた値が受け取れます。
ただし、通常はこうして得られる値は配列の形になっているので、ここから更に値を取り出します。
では、これも実際にやってみましょう。

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf?id=123&name=aaa

図 5.5 3:Thymeleafの色々な使い方(パラメータへのアクセス)

コントローラーを介さず、テンプレート内から直接送られた値を利用しているのがわかったでしょうか。
ここでは、値を${param.id[0]} ${param.name[0]}というようにして取り出しています。このようにparam内のidやnameの配列の最初の要素を指定することで、値を取り出すことができるのです。

5.5.6 テキストリテラルの記述

既に動作確認を終えましたが、ここで記述しているth:textの値を見ると、ダブルクォートの中に、更にシングルクォートで値が記述されていることがわかります。これは、OGNLでテキストリテラルを記述する際の書き方です。

1つのテキストリテラルをそのまま表示する場合は、ダブルクォート内に直接テキストを書けばいいのですが、いくつかのリテラルをつなぎ合わせるような場合は、ダブルクォート内に更にシングルクォートでテキストリテラルを記述することができます。

■例

上記の例文は、どちらも同じ「one two three」というテキストを出力しますが、後者はそれぞれの単語を+記号でつなぎ合わせるようにしていますね。こんな具合に、ダブルクォートの中で更に式を使って値を組み立てることができます。

5.5.7 条件分岐の「th:if」

まず、以下のアドレスでアプリケーションにアクセスしてみましょう。
URL:http://localhost:8080/thymeleaf


図 5.5 4:送信されていないパラメータにアクセスしようとするとエラーになる

先ほど記述した処理により、パラメータが送信されていない状態でアクセスしようとして、エラーが発生してしまっています。このままでは、この後もパラメータを指定し続けなくてはならず、とても手間が掛かりますね。

詳しくは次の節でご説明しますが、Thymeleafには条件式や繰り返しなどを行うための機能も用意されています。そこで、先ほど記述したパラメータへアクセスするための処理を「条件分岐」を利用して、送信されていた場合のみ表示するように修正してみましょう。

まずは、基本的な構文から見ていきます。

条件として設定したものが「true」の場合に、このタグおよびその内部にあるタグを表示します。

条件として設定したものが「false」の場合に、このタグおよびその内部にあるタグを表示します。

Java標準のif構文とは少し勝手が異なりますが、つまり、「表示そのものをON/OFFする」といった際に使います。これらの属性で注意が必要なのが、true/falseの判断が真偽値だけではない、という点です。

■trueと判断されるもの
  • true
  • ゼロ以外の数値
  • ”0”、”off”、”no”といった値以外の文字列
■falseと判断されるもの
  • false
  • 数値のゼロ
  • ”0”、”off”、”no”といった文字列

offやnoなどの文字列を理解して利用する分には問題ありませんが、意図せずON/OFFしてしまわないように注意してください。それでは先ほどのエラーを修正していきましょう。

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf

図 5.5 5:パラメータが送信されない場合でもエラーが発生しなくなる

パラメータが送信されない場合でもエラーが発生しなくなりましたね。

ここではth:ifの条件に「param.xx != null」が設定されています。この条件がtrueの場合、つまりパラメータが送信されている場合のみ、このタグが表示されるようになります。

5.5.8 メッセージ式

${ }という変数式以外にも、Thymeleafでは利用できるものがあります。「メッセージ式」です。
これは、プロジェクトにあらかじめ用意しておいたプロパティファイルから値を取り出し、表示します。Javaでは、プロパティファイルにあらかじめテキストをまとめておき、それを読み込んで利用することがよくあります。メッセージ式は、これをテンプレート内から直接利用できるようにしたものといえるでしょう。
メッセージ式は、以下のように記述します。

${ }ではなく、#{ }という形で記述するのが特徴です。{ }内には、取り出す値を指定します。これは、プロパティファイルに記述する値に応じて記述します。

では、実際にやってみましょう。まず、プロパティファイルを用意する必要があります。これは、一般的なテキストファイルとして作成します。
<ファイル>メニューの<新規>内から、<ファイル>メニューを選んでください。


図 5.5 6:<ファイル>メニューを選ぶ

現れたダイアログウィンドウで、プロジェクトの「resources」フォルダを選択し、「ファイル名」の欄に「messages.properties」と入力して「完了」ボタンを押し終了します。これで「resources」フォルダ内にプロパティファイルが作成されます。


図 5.5 7:<ファイル>メニューを選ぶ

作成されたファイルを開き、そこに以下のようにプロパティの値を記述しておきましょう。

【ファイル名:messages.properties】

ここでは、howto.titleとhowto.messageという2つの値を用意しておきました。では、これらをテンプレートで表示させましょう。テンプレートファイルを以下のように修正します。

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf

図 5.5 8:プロパティファイルに記述した値が表示される

ブラウザからアクセスしてみると、messages.propertiesに記述した値がページに表示されます。
先ほどテンプレートに記述した通り、#{howto.title}というようにプロパティファイルの値の名前を指定するだけで、その値がここに出力されるようになるのです。

5.5.9 プロパティファイルとローカライズ

プロパティファイルとメッセージ式は、どういう働きをするのでしょうか。一つは「値をテンプレートから分離する」という点にあるでしょう。表示されるコンテンツをすべてテンプレート内にリテラルとして記述してしまうより、メッセージ式を書いておいて、値そのものはプロパティファイルで一括管理した方が後々のメンテナンス性も良くなります。

また、Javaのプロパティファイルがローカライズに多用されるように、Spring Bootの場合もローカライズのために利用することが多いでしょう。例えば、messages.propertiesと同じ場所に「messages_○○.properties」というファイルを作成し、ここに指定した言語の値を保管しておけば、その言語の環境ではこのファイルから値を取り出して表示するようになります。

実際に試してみましょう。「resources」フォルダの中に、「messages_ja.properties」という名前のファイルを作成してください。そして、この中に日本語の値を用意します。

【ファイル名:messages_ja.properties】

ただし、実際に試してみるとわかりますが、STSではプロパティファイルに日本語を記述するとUnicodeコードへとリアルタイムにエスケープされ、以下のような表示に変わります。

【ファイル名:messages_ja.properties】

これが日本語プロパティファイルの内容になります。STSでは、この変換処理が自動で行なわれます。

それではファイルができたら、以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf


図 5.5 9:メッセージが日本語に変わった

ブラウザの言語が日本語に設定されていれば、日本語で表示されます。

5.5.10 リンク式とhref

Webページでは、URLを指定したリンクもさまざまなところで利用されます。リンクを指定する専用の式が用意されています。

これは、基本的にURLを指定するような属性(<a>タグのhrefなど)で利用します。例えば、@{/index}と記述すれば、/indexへのリンクを指定することができます。
「リンクなんて、普通にテキストとして書けばいいだろう」と思う人も多いかもしれませんが、例えば、他の変数などと組み合わせてリンクのアドレスを指定するような場合には必要となってきます。
これも、実際に簡単な例を試しておきましょう。

【ファイル名:ThymeleafController.java】

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf


図 5.5 10:リンクには、/detail/999というようにコントローラーから渡された値が追加される

「別のページ」のリンクはそのまま表示されているだけなので、大丈夫かと思います。
ここでのポイントは変数を利用した「詳細ページ」のリンクです。テンプレートだけでなくコントローラー側の処理も修正していますね。コントローラーから「user_id」という名前で「999」という値を渡し、それをth:hrefで表示しています。

ポイントとなる点を分解して考えてみましょう。

つまり、変数を処理する命令文から逆に見ていくと、以下のようになります。

① ${user_id}という変数が展開される

@{/detail/{id}/(id=999)}

② {id}という文字列と値が置換される

@{/detail/999/}

③ リンクのアドレスとして表示される

href=”/detail/999/”

少しややこしく感じるかも知れませんが、慣れておくと便利かと思いますよ。

5.5.11 選択オブジェクトへの変数式

変数式は、基本的にコントローラー側に用意した値をそのまま出力するだけのものです。が、これは数値やテキストといったシンプルな値ならばいいのですが、オブジェクトを利用するようになると扱いに困ってしまいます。

もちろん、例えば ${object.name} といった具合にオブジェクトのプロパティやメソッドを指定して書けばいい、というのは確かですが、オブジェクト内に多数の値がある場合、いちいち記述するのは面倒ですし、オブジェクト名が変更されたりしたときにすべての名前をまた書き換えないといけないのは大変です。

このような場合、オブジェクトを指定し、その選択されたオブジェクト内の値を取り出すための専用の変数式が用意されています。
この変数式は、オブジェクトを扱う変数式の内部で利用します。

あるタグに「th:object」という属性を使ってオブジェクトを設定します。こうすることで、そのタグの内部で、*{ }による変数式が使えるようになります。このアスタリスクによる変数式では、オブジェクト内のプロパティなどを名前だけで指定できるようになります。

では、実際に使ってみましょう。これは、コントローラー側でオブジェクトを用意しなければいけません。

【ファイル名:ThymeleafController.java】

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf

図 5.5 11:userに保管したUserオブジェクトの値を表示する

それでは、ポイントを簡単に確認していきましょう。

【ファイル名:ThymeleafController.java】

    // 選択オブジェクト用サンプル
    User user = new User("神田太郎", 25);
    mav.addObject("user", user);
    

ここでは、mav.addObject(“user”, user); という形で、new Userしたインスタンスを ”user” という名前にしてModelAndViewに保管しています。これをテンプレート側で利用しよう、というわけです。

【ファイル名:howto.html】

次に、テンプレート側の変数式がどうなっているか見てみると、上記のような構造になっていることがわかるでしょう。
<table>タグに、th:objectを使って ${user} が設定されています。これで、この<table>タグ内では、*{ } でuser内のプロパティなどを直接扱えるようになります。後は、 th:text=”*{name}” といった具合に値を出力していくだけです。

このやり方を見ればわかるように、オブジェクトに関する記述は th:object に1つあるだけです。ということは、もし、他のオブジェクトを用意してそちらに変更するような場合も、この1箇所を書き換えるだけで済む、ということになります。

5.5.12 リテラル置換

変数式の中にいくつかの値を組み合わせてテキストを出力させる場合、”’A’ + ‘B’” というようにダブルクォート内に更にテキストリテラルをつなぎ合わせて書いてきました。これで一応はテキストを作成できますが、もっとシンプルな書き方ができた方が良いですね。

これには「リテラル置換」と呼ばれる書き方が用意されています。以下のように記述します。

テキストの前後に | 記号を付けて記述します。普通のテキストと何が違うのかというと、この中には変数式を直接書き込むことができるのです。
では早速、userに渡される値をつなぎ合わせてテキストを表示させてみることにしましょう。

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。 URL:http://localhost:8080/thymeleaf


図 5.5 12:Userの内容を使ってメッセージを表示する

ブラウザからアクセスすると、「名前は 神田太郎、年齢は 25歳 です。」と表示されます。これは、テンプレートに渡したuserの値を使ってメッセージを作成しています。

【ファイル名:howto.html】

テキストリテラルの中に、*{name}*{age} という変数式が直接書き込まれています。こんな具合に、+記号でリテラルをつなぎ合わせる必要も無く、自然なテキストに近い形で変数式を埋め込んで利用することができます。

5.5.13 HTMLコードの出力

ここまでは、すべてテキストを出力させるだけでした。では、テキストではなく、HTMLのコードを出力させたい場合はどうするのでしょうか。早速試してみましょう。

【ファイル名:ThymeleafController.java】

【ファイル名:howto.html】

以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/thymeleaf

図 5.5 13:Userの内容を使ってメッセージを表示する

さて、もうお気付きかとは思いますが、違う点は「th:text」と「th:utext」だけです。

【ファイル名:howto.html】

これまで使っていた「th:text」はテキストを表示する際に「エスケープ処理」を自動で行ってくれていました。これはThymeleafに内蔵されている機能です。Thymeleafは変数式でテキストを出力する際、安全のためにHTMLタグをすべてエスケープ処理するようになっているのです。

しかし、今回のようにHTMLを含む文字列を表示したい場合、それでは困りますね。ただ、そういった場合は「th:text」という部分を「th:utext」に変更するだけで済むようになっています。
th:utextは、アンエスケープ(エスケープしない)テキストを出力するための属性です。これを使うことで、設定されたテキストをそのままの状態で出力できます。

NEXT>> 5.6 構文・インライン・レイアウト