Thymeleaf th:attrで属性を動的に切り替える方法|Spring MVCで学ぶテンプレートエンジンの基本
新人
「先輩、ThymeleafでHTMLの属性を動的に変更したいんですが、どうすればいいですか?」
先輩
「それならth:attrを使うのが便利だよ。Thymeleafには、属性をサーバー側の値によって切り替える仕組みがあるんだ。」
新人
「なるほど。属性って、例えばボタンのdisabledとかリンクのhrefとかですか?」
先輩
「そのとおり。th:attrを使えば、条件に応じて属性値を変えたり、付け外ししたりできるんだ。Spring MVCと一緒に使うととても強力だよ。」
1. Thymeleafとは何か(テンプレートエンジンとしての役割)
Thymeleaf(タイムリーフ)は、Spring MVCでよく使われるテンプレートエンジンです。テンプレートエンジンとは、HTMLファイルの中に動的な要素を埋め込み、サーバー側で値を置き換えて出力する仕組みのことです。たとえば、ユーザー名やボタンの状態などをサーバーのデータに合わせて変更できます。
Thymeleafの魅力は、HTMLファイルが「そのままブラウザでも開ける」ナチュラルテンプレート構文を採用している点です。これにより、デザイナーとエンジニアが同じファイルを使って開発でき、保守性の高い設計が可能になります。
Thymeleafでは、HTMLタグにth:で始まる属性を追加することで、サーバー変数の値を反映できます。例えば、次のように書くとサーバーから渡された変数が表示されます。
<p th:text="'こんにちは、' + ${userName} + 'さん!'"></p>
上記の例では、コントローラで設定したuserNameの値がHTML内に反映されます。このように、ThymeleafはJavaコードで生成したデータをテンプレートに自然に埋め込むことができます。
特に、フォームやリンク、ボタンの状態を切り替えるときに、動的属性設定がよく使われます。その中心的な役割を担うのがth:attrです。
2. Spring MVCでThymeleafを使うための基本設定(pleiades+Gradle+@Controller構成)
次に、Spring MVCでThymeleafを使うための準備を行いましょう。開発環境はpleiadesを使用し、依存関係はGradleで管理します。MavenではなくGradleを使う点に注意してください。
pleiadesでSpringプロジェクトを作成するときに、「Spring Web」と「Thymeleaf」にチェックを入れておくと、自動的に必要な依存関係が追加されます。もし手動で設定する場合は、build.gradleに次のように記述します。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
}
次に、コントローラクラスを作成します。Springでは、画面表示用のコントローラは@Controllerを使用します。@RestControllerではなく@Controllerを使うことが重要です。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AttrController {
@GetMapping("/attr")
public String showAttrPage(Model model) {
boolean enabled = true;
model.addAttribute("enabled", enabled);
return "attr-sample";
}
}
このコントローラでは、enabledという変数をテンプレートに渡しています。この値をHTML側で利用し、ボタンやリンクの属性を動的に制御できます。
このように、Spring MVCとThymeleafを組み合わせることで、コントローラで設定した値をもとにHTMLの属性を柔軟に変更できるようになります。
3. th:attrとは?(属性を動的に切り替える基本的な仕組み)
th:attrは、HTMLタグの任意の属性を動的に変更するためのThymeleafの機能です。例えば、ボタンを「有効・無効」にしたり、リンクの遷移先を動的に変更したりすることができます。
基本構文はとてもシンプルで、HTMLタグにth:attr="属性名=値"という形で指定します。静的な属性をサーバー変数の値で上書きする仕組みです。
<button th:attr="disabled=${!enabled}">送信</button>
上記の例では、${!enabled}がtrueの場合、ボタンにdisabled属性が追加されます。つまり、enabledがfalseのときにボタンが無効化されます。
実際に出力されるHTMLは次のようになります。
<button disabled>送信</button>
もしenabledがtrueであれば、属性は出力されません。
<button>送信</button>
このように、Thymeleaf th:attrを使うことで、属性の有無や値を動的に制御できます。これにより、ボタンやリンク、フォームの動作をサーバーサイドの条件に応じて切り替えることが可能です。
また、th:attrでは複数の属性を一度に指定することもできます。たとえば、リンクのURLとタイトルを同時に変更する例を見てみましょう。
<a th:attr="href=${linkUrl}, title=${linkTitle}">詳細ページ</a>
上記のようにカンマ区切りで複数の属性を指定できます。Spring MVCのコントローラ側でlinkUrlやlinkTitleを設定すれば、テンプレートに反映されます。
この機能は、ページ遷移や条件付きリンクの制御に非常に便利です。動的属性設定を使うことで、複数の画面要素を柔軟に変更できるようになります。
4. th:attrの基本構文と使い方
ここからは、Thymeleaf th:attrの基本構文と使い方を詳しく見ていきましょう。前章で紹介したように、th:attrはHTMLタグの属性をサーバー側で動的に切り替えるための仕組みです。Thymeleafでは、テンプレートエンジンの機能を使って、サーバー変数をHTMLの中に埋め込みます。
基本構文は次のようになります。
<tag th:attr="属性名=${式}">内容</tag>
タグの中で指定する属性名は、HTMLに存在する任意の属性です。たとえば、href、src、disabled、titleなどを動的に変更することができます。式には、コントローラで渡した変数や計算式を記述します。
例えば、リンクのURLをコントローラの値によって変える場合は次のように書けます。
<a th:attr="href=${pageUrl}">ページへ移動</a>
ここでpageUrlはSpring MVCの@Controllerから渡された値です。コントローラの例を見てみましょう。
@Controller
public class LinkController {
@GetMapping("/link")
public String linkPage(Model model) {
model.addAttribute("pageUrl", "/nextPage");
return "link-sample";
}
}
このようにすると、Thymeleafは${pageUrl}を実際の文字列/nextPageに置き換えてHTMLを出力します。ブラウザ上では次のようになります。
<a href="/nextPage">ページへ移動</a>
このように、動的属性設定を使うことで、バックエンドの変数に応じてHTML属性を柔軟に変えることができます。条件式を組み合わせることでさらに高度な制御も可能です。
5. 条件式(if文や三項演算子)を使って属性を切り替える方法
Thymeleaf th:attr 条件分岐を使うと、より細かい制御ができます。特にボタンやリンクを表示・非表示にしたり、属性値を変更したい場合に便利です。Thymeleafでは、Javaのように三項演算子(条件 ? 値1 : 値2)を使って条件分岐が可能です。
次の例では、ユーザーが管理者かどうかでボタンの表示文言と属性を切り替えます。
<button th:attr="class=${isAdmin} ? 'btn-admin' : 'btn-user'"
th:text=${isAdmin} ? '管理画面へ' : '一般ユーザー画面へ'>
</button>
この例では、isAdminがtrueの場合、ボタンのclass属性がbtn-adminになり、表示テキストも「管理画面へ」となります。falseの場合は別のクラスとテキストが設定されます。
コントローラ側では、条件に応じた変数をModelに追加しておきます。
@Controller
public class RoleController {
@GetMapping("/role")
public String showRole(Model model) {
boolean isAdmin = false;
model.addAttribute("isAdmin", isAdmin);
return "role-sample";
}
}
また、条件式の中ではif文の代わりにth:if属性を使うことも可能です。th:ifはタグそのものを表示・非表示にする場合に使います。一方でth:attrは「属性だけを切り替える」用途に向いています。
例えば、ボタンをログイン状態によって無効化したい場合は次のように書けます。
<button th:attr="disabled=${!isLogin}">送信</button>
この構文では、isLoginがfalseのときだけボタンが無効化されます。もし式の書き方を間違えてth:attr="disabled=!isLogin"のように書くと、Thymeleafは!isLoginを文字列と認識してしまうため動作しません。式は必ず${ }の中に書く必要があります。
このように、条件式を活用することでSpring MVCの変数と連携しながら、画面の動作を柔軟に制御できます。
6. th:attrとth:attrappendの違い(上書きと追加の違い)
最後に、th:attrとよく混同されるth:attrappendの違いを確認しておきましょう。どちらもHTMLの属性を操作しますが、挙動が異なります。
th:attrは属性を上書きします。一方でth:attrappendは既存の属性に追加します。
具体例を見てみましょう。次のようなHTMLを想定します。
<a class="btn" th:attr="class=${extraClass}">ボタン</a>
ここでextraClassに「btn-primary」が設定されている場合、最終的に出力されるHTMLは次のようになります。
<a class="btn-primary">ボタン</a>
もともとの「btn」が上書きされて消えてしまいます。これを防ぎたいときにth:attrappendを使います。
<a class="btn" th:attrappend="class=' '+${extraClass}">ボタン</a>
上記のように書くと、既存のclass属性にスペース区切りで値を追加できます。出力結果は次のようになります。
<a class="btn btn-primary">ボタン</a>
このようにth:attrappendを使うことで、既存の属性値を残しつつ、新しいクラス名や属性を加えることができます。CSSクラスを条件によって動的に追加したい場合や、ボタンに複数のスタイルを組み合わせたいときに非常に便利です。
また、反対に属性の前に追加したい場合はth:attrprependを使うこともできます。これにより、HTMLの属性操作がさらに柔軟になります。
初心者がよく間違えるのは、th:attrとth:attrappendを混同して使うケースです。上書きと追加の動作を明確に理解しておくことで、意図しない画面崩れやCSSの適用漏れを防ぐことができます。
このように、Thymeleafではテンプレートエンジンの機能を活かして、属性を自在に制御することができます。動的属性設定を正しく使えば、Spring MVCのデータを見た目や動作に反映させる表現力の高いテンプレートを作成できます。
7. 複数の属性を同時に切り替える方法
ここでは、Thymeleaf th:attrを使って、複数の属性を同時に切り替える方法を紹介します。実務では、ボタンの状態だけでなく、リンクのURLやタイトル、スタイルなどを同時に変更したい場面があります。Thymeleafでは、カンマで区切るだけで複数の属性を一度に指定できます。
たとえば、ユーザーが管理者である場合にだけリンクのスタイルとタイトルを変更したい場合、次のように書きます。
<a th:attr="href=${isAdmin} ? '/admin' : '/home',
title=${isAdmin} ? '管理画面へ' : 'ホームへ',
class=${isAdmin} ? 'link-admin' : 'link-user'">ページリンク</a>
このように1つのth:attrの中で複数の属性をまとめて制御できます。条件分岐を組み合わせることで、表示される属性を一括で切り替えることができます。
もしコントローラ側でisAdminを設定しておけば、テンプレートはそれに応じて動的に変化します。これは、複雑な画面制御をシンプルに実装する上で非常に有効です。
また、属性の値にnullや空文字を設定すると、Thymeleafはその属性を出力しません。つまり、条件に応じて属性自体を削除することも可能です。これにより、余分なHTMLを出力せずにクリーンなマークアップを維持できます。
このように複数属性の同時切り替えを活用すると、1つのテンプレートで多様な状態を柔軟に表現できるようになります。特にSpring MVCと組み合わせることで、サーバーサイドで処理した結果をそのまま画面制御に反映できる点が魅力です。
8. コントローラとテンプレートの連携による実践例
ここでは、実際にSpring MVCのコントローラとThymeleafテンプレートを連携させ、動的属性設定を行う具体例を紹介します。初心者が理解しやすいように、シンプルなログイン画面を例に考えましょう。
まず、コントローラを作成します。ユーザーのログイン状態によってボタンやリンクの属性を変える例です。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class LoginController {
@GetMapping("/loginStatus")
public String showLoginPage(Model model) {
boolean isLogin = false;
String userName = "ゲスト";
model.addAttribute("isLogin", isLogin);
model.addAttribute("userName", userName);
return "login-status";
}
}
次に、テンプレートファイルlogin-status.htmlでth:attrを使いましょう。
<div>
<p th:text="'こんにちは、' + ${userName} + 'さん'"></p>
<a th:attr="href=${isLogin} ? '/logout' : '/login',
title=${isLogin} ? 'ログアウトします' : 'ログインページへ移動'"
th:text=${isLogin} ? 'ログアウト' : 'ログイン'></a>
</div>
この構成では、ログインしていない場合はリンクが「ログイン」となり、href属性が/loginになります。ログイン済みなら/logoutに変わります。
このように、Spring MVCのコントローラでModelに値を追加し、Thymeleaf側で条件分岐を行うことで、状態に応じてHTML属性を動的に切り替えることができます。
また、同時に複数の属性を変更できるため、テンプレートとバックエンドの連携が非常にスムーズです。Java側のロジックを最小限に抑え、テンプレート側で柔軟に条件制御を行う設計は、保守性の高いSpringアプリケーションにおいて重要なポイントとなります。
さらに、Thymeleafでは式の中で文字列連結や条件式の入れ子も可能です。これにより、より複雑な画面ロジックをテンプレート上でシンプルに表現することができます。
9. よくあるエラーとデバッグのコツ(th:attrが効かないときの原因と対処)
最後に、初心者がよくつまずくポイントを整理しておきましょう。Thymeleaf th:attr 条件分岐を使っても属性が反映されない場合、多くは文法ミスかModelの設定ミスが原因です。
まず確認すべきは、式の書き方です。Thymeleafではすべての式を${ }で囲む必要があります。これを忘れると単なる文字列として扱われ、動的に評価されません。
たとえば、次のような間違いがよくあります。
<!-- 間違い例 -->
<button th:attr="disabled=!isLogin">送信</button>
この書き方だと、!isLoginが文字列として処理され、ボタンは常に無効化されません。正しくは次のように記述します。
<!-- 正しい例 -->
<button th:attr="disabled=${!isLogin}">送信</button>
また、コントローラでModelに属性を追加し忘れるのもよくあるミスです。テンプレート側で参照している変数が存在しない場合、Thymeleafはエラーを出さずに空欄として扱うため、見た目では気づきにくい点に注意が必要です。
さらに、HTML側の静的属性が優先されているケースもあります。たとえば、hrefやclassを静的に指定していると、th:attrで上書きされないことがあります。この場合は、静的属性を削除してth:attrだけで制御するか、th:attrappendを使って追加する方法に切り替えましょう。
また、条件式でnullを扱うときは、評価結果が空文字になることがあります。安全に制御するには、th:ifと組み合わせる方法も効果的です。
例えば、ログイン中のみボタンを表示したい場合は次のように書きます。
<button th:if="${isLogin}" th:attr="class='btn-login'">ログアウト</button>
このようにすることで、条件を満たさない場合はボタンそのものがHTMLに出力されません。これにより、不要な空要素を防ぎつつ、確実に画面制御が行えます。
デバッグ時には、Thymeleafが最終的に生成したHTMLをブラウザで「検証」から確認するのがおすすめです。サーバー側でレンダリングされた後のHTMLを直接見ることで、th:attrの結果を正確に把握できます。
また、サーバーログに出力されるレンダリングエラーもチェックしましょう。変数名の誤りや条件式の構文ミスがある場合、Thymeleafは詳細なスタックトレースを出力します。特に「VariableExpression」関連のエラーは、Modelで指定した変数名の不一致が原因であることが多いです。
このように、th:attrが効かないときの原因は文法ミス・変数未設定・静的属性の競合などが中心です。これらを一つずつ確認すれば、ほとんどの不具合は解消できます。ThymeleafとSpring MVCのテンプレート連携を正しく理解していれば、動的な属性変更を安定して実装できるようになります。