Thymeleafでよくあるエラーとその解決法まとめ【初心者向け完全ガイド】
新人
「先輩、Thymeleafって最近よく聞くんですが、何に使うんですか?」
先輩
「Thymeleafは、HTMLテンプレートを使ってWebページを動的に生成するテンプレートエンジンなんだ。Spring Frameworkと一緒によく使われているよ。」
新人
「なるほど、でも使ってみるとエラーばかり出てきて困ってます…」
先輩
「それはよくある悩みだね。初心者がつまずきやすいThymeleafのエラーと解決方法を一緒に確認していこう!」
1. Thymeleafとは?初心者向けにわかりやすく解説
Thymeleaf(タイムリーフ)は、JavaのWebアプリケーションで使われるテンプレートエンジンの一つです。特にSpring BootやSpring MVCと組み合わせて使われることが多く、HTMLファイルにJavaのデータを埋め込んで、ブラウザに動的なWebページを表示するために利用されます。
例えば、コントローラから渡されたユーザー名や一覧データを画面に表示したい場合、Thymeleafのth:textやth:eachなどの属性を使って値を埋め込むことができます。
Thymeleafの特徴は、HTMLテンプレートをブラウザで直接開いてもエラーにならず、プレーンなHTMLとしても表示できる点です。これは学習中の初心者にとっても大きな利点です。
開発環境としては、Pleiades + GradleでSpring Bootプロジェクトを構成し、@Controllerを使ってThymeleafの画面にデータを渡す方法が一般的です。
2. 初心者がよく遭遇するThymeleafの初歩的なエラーとその解決法
Thymeleafを使っていると、初心者が特につまずきやすいエラーがいくつかあります。ここでは代表的なエラーと、その解決方法について解説します。
(1)変数がnullのまま出力しようとしてエラーになる
Thymeleafでは、存在しないオブジェクトやnullの変数にアクセスしようとすると例外が発生したり、表示がうまくいかないことがあります。
以下は典型的な例です。
<p th:text="${user.name}">名前</p>
このコードでuserオブジェクト自体がコントローラから渡されていない場合、実行時にエラーが発生します。
このような場合、コントローラでModelに値を設定しておく必要があります。
@Controller
public class SampleController {
@GetMapping("/hello")
public String hello(Model model) {
User user = new User();
user.setName("太郎");
model.addAttribute("user", user);
return "hello";
}
}
このように、Thymeleafテンプレートで使うオブジェクトは、必ずコントローラでmodel.addAttributeを使って渡しておく必要があります。
(2)式展開の文法ミス
Thymeleafでは${}の中に変数名を書くことで値を出力できますが、これを間違えると正常に表示されません。
例えば、次のようなコードは間違いです。
<p th:text="$user.name">名前</p> <!-- 誤り -->
正しくは、次のように${}で囲む必要があります。
<p th:text="${user.name}">名前</p> <!-- 正解 -->
また、ダブルクォート(")で囲むのを忘れるとブラウザでの解釈が不正になり、レイアウトが崩れる原因にもなるので注意しましょう。
(3)HTMLに埋め込んだ動的データが文字化けする
Thymeleafではデフォルトで出力値がHTMLエスケープされるため、特殊文字を含むデータを出力したときに文字化けのように見えることがあります。
その場合、th:utextを使ってHTMLとしてそのまま表示させることで回避できます。
<div th:utext="${htmlContent}">内容</div>
ただし、ユーザー入力をそのままth:utextで出力すると、XSS(クロスサイトスクリプティング)攻撃のリスクがあるので、信頼できるデータにのみ使うようにしましょう。
(4)テンプレートファイルが見つからず、404エラーになる
これはテンプレートファイルの配置場所が正しくない場合によく起こるエラーです。Spring Bootでは、デフォルトでテンプレートファイルはsrc/main/resources/templatesに配置する必要があります。
例えば、ファイル名がhello.htmlの場合、コントローラでは以下のように指定します。
@Controller
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello"; // 拡張子.htmlは不要
}
}
このように、ファイル名はテンプレートディレクトリ直下に置き、拡張子を省略して指定するのがThymeleafの基本ルールです。
3. コントローラとテンプレートの連携ミスとその解決方法
Thymeleafを使った開発で特によくあるのが、コントローラとテンプレートの連携ミスです。特に初心者に多いのが、Modelに値を渡し忘れて、テンプレートで変数がnullになるケースです。
例えば、以下のようなHTMLテンプレートがあったとします。
<p th:text="${product.name}">商品名</p>
このテンプレートではproductというオブジェクトのnameプロパティを表示しようとしていますが、コントローラでproductがModelに追加されていない場合、テンプレート処理時にnullとなり、Thymeleafエラーが発生します。
コントローラでは、以下のようにModelにデータを正しく渡す必要があります。
@Controller
public class ProductController {
@GetMapping("/product")
public String showProduct(Model model) {
Product product = new Product();
product.setName("ノートパソコン");
model.addAttribute("product", product);
return "product";
}
}
このようにmodel.addAttributeを使ってproductという名前でオブジェクトを渡すことで、テンプレート側でも${product.name}が正しく表示されるようになります。
開発中に変数が表示されない場合は、コントローラ側でModelに値を渡しているか、オブジェクト名がテンプレートと一致しているかを必ず確認しましょう。
4. フォーム送信時のバリデーションエラーとその対処法
Thymeleafでは、フォームとJavaのオブジェクトを結びつけてデータバインディングする機能があります。ただし、フォーム入力にバリデーションを設定した場合、正しくエラー処理をしないと画面にエラーが表示されなかったり、サーバーで例外が発生したりします。
(1)th:fieldを使ったフォームバインディングの基本
Thymeleafでは、フォームの各入力項目にth:fieldを使ってJavaのオブジェクトと関連付けを行います。以下は、名前とメールアドレスを入力する基本的なフォームの例です。
<form th:action="@{/register}" th:object="${userForm}" method="post">
<label>名前:</label>
<input type="text" th:field="*{name}" />
<label>メールアドレス:</label>
<input type="email" th:field="*{email}" />
<button type="submit">登録</button>
</form>
この場合、コントローラでは以下のようにModelにuserFormオブジェクトを追加しておく必要があります。
@Controller
public class RegisterController {
@GetMapping("/register")
public String showForm(Model model) {
model.addAttribute("userForm", new UserForm());
return "register";
}
}
(2)@ValidとBindingResultでエラーメッセージを表示する
バリデーションチェックを行うには、コントローラで@Validを使ってリクエストされたオブジェクトを検証し、その直後にBindingResultを受け取ることで、エラーの有無を確認できます。
@PostMapping("/register")
public String submitForm(@Valid @ModelAttribute("userForm") UserForm form,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
return "register"; // エラーがあればフォームに戻す
}
// 正常時の処理(例:データ保存)
return "success";
}
上記のように、BindingResultのhasErrors()メソッドでエラーの有無を確認し、エラーがある場合は再度フォーム画面に戻すという処理が一般的です。
(3)テンプレートにエラーメッセージを表示する
フォームの各項目ごとに、バリデーションエラーが発生した場合は、th:errorsを使って画面上にエラーメッセージを表示することができます。
<form th:action="@{/register}" th:object="${userForm}" method="post">
<label>名前:</label>
<input type="text" th:field="*{name}" />
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
<label>メールアドレス:</label>
<input type="email" th:field="*{email}" />
<div th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
<button type="submit">登録</button>
</form>
これにより、ユーザーが入力した値に不備がある場合、どのフィールドが原因でエラーになっているのかが明確に表示されるようになります。
(4)バリデーション用のDTOクラスを作成する
バリデーションチェックは、DTOクラス(フォームオブジェクト)にアノテーションをつけることで設定できます。以下はUserFormというDTOの例です。
public class UserForm {
@NotBlank(message = "名前は必須です")
private String name;
@Email(message = "正しいメールアドレスを入力してください")
@NotBlank(message = "メールアドレスは必須です")
private String email;
// ゲッター・セッター省略
}
このように、@NotBlankや@Emailといったバリデーション用のアノテーションを使うことで、Thymeleafのフォームに対してサーバーサイドでしっかりとチェックを行うことが可能です。
Thymeleafでフォームバリデーションを正しく動かすためには、th:fieldで正しいプロパティに紐づけること、@ValidとBindingResultをセットで使うこと、そしてエラーをテンプレート内で適切に表示することが重要です。
5. テンプレート内の構文エラーとその解決方法
Thymeleafでは、テンプレートファイルの中に書く構文を間違えると、画面が正しく表示されなかったり、予期せぬ動作になったりします。特に初心者に多いミスとしては、th:eachの使い方の誤りや、フラグメントの呼び出し方の間違いなどがあります。
(1)th:eachの構文ミス
繰り返し処理を行うためのth:eachは、リストなどのコレクションデータを画面に表示する際によく使われますが、構文を間違えるとループ処理が実行されません。
以下は、正しくない例です。
<ul>
<li th:each="item: items" th:text="${item.name}"></li>
</ul>
item: itemsという表現はThymeleafではエラーになります。正しくは次のように書きます。
<ul>
<li th:each="item : ${items}" th:text="${item.name}"></li>
</ul>
このように、変数 : ${リスト名}の形式で書くことが正しい構文です。
(2)フラグメントの呼び出しミス
テンプレートの共通部分(ヘッダーやフッターなど)を分離して再利用する場合、th:replaceやth:insertを使ってフラグメントを読み込みます。しかし、呼び出し方を間違えるとエラーになります。
以下のように、フラグメントの定義と呼び出し方に注意しましょう。
定義側(header.html)
<div th:fragment="siteHeader">
<header>サイト共通ヘッダー</header>
</div>
呼び出し側
<div th:replace="header :: siteHeader"></div>
ファイル名 :: フラグメント名という構文が正しい形式です。この::の記述が抜けたり、ファイル名が間違っていたりすると、Thymeleafのテンプレート読み込みエラーが発生します。
6. ローカル環境での表示トラブルとその対処法
Pleiades + Gradle環境でThymeleafテンプレートを開発していると、エラーではないが画面に変更が反映されないといった「表示トラブル」が発生することがあります。ここでは、特によくある二つの原因と解決方法を紹介します。
(1)キャッシュによるテンプレートの更新が反映されない問題
Spring Bootでは、デフォルトでThymeleafのテンプレートがキャッシュされる設定になっているため、テンプレートファイルを修正しても画面に反映されないことがあります。これは開発中には非常に不便です。
この場合、application.propertiesに以下の設定を追加してキャッシュを無効にします。
spring.thymeleaf.cache=false
この設定を入れることで、テンプレートを更新するたびに即時反映されるようになります。開発中はこの設定を有効にし、本番環境ではキャッシュを有効に戻すのが推奨されます。
(2)テンプレートや静的ファイルのパス指定ミス
ローカル環境で画像やCSSファイルが読み込まれない場合、テンプレート内でのパス指定ミスが原因であることがよくあります。
Spring Bootでは、静的リソースはsrc/main/resources/staticに配置し、テンプレートからはルートパスからのパス指定で読み込むのが基本です。
正しい例:
<link rel="stylesheet" th:href="@{/css/style.css}" />
<img th:src="@{/images/logo.png}" alt="ロゴ" />
このようにth:hrefやth:srcを使って正しく記述することで、パスの解決ミスを防ぐことができます。
7. エラーが起きたときに確認すべきポイント
Thymeleafを使っていると、思わぬエラーに遭遇することがありますが、慌てずに以下のポイントを順番に確認することで、原因を特定しやすくなります。
- テンプレートファイルのパスは正しいか?
テンプレートはsrc/main/resources/templates内に配置されているかを確認。 - モデルに必要な属性が追加されているか?
コントローラでmodel.addAttributeを忘れていないかをチェック。 - 構文エラーがないか?
th:eachやth:replaceの記述が正しいか確認。 - キャッシュの影響で古い画面が表示されていないか?
spring.thymeleaf.cache=falseの設定を活用。 - フォームバリデーションの処理が正しく構成されているか?
@ValidとBindingResultをセットで使っているか。 - エラーメッセージはテンプレートに表示されるようにしているか?
th:errorsを使って正しい場所に表示されているか確認。
これらのポイントを丁寧に見直すことで、Thymeleafのテンプレートエラーのほとんどは解決可能です。特に初心者のうちは、1つずつ確認する習慣をつけることが、安定した開発につながります。
まとめ
このまとめでは、Thymeleafを使用する際に初心者が遭遇しやすいエラーや、その解決方法を総合的に振り返りながら、検索エンジンに高く評価されやすい重要語句を多く盛り込み、より深い理解につながるように整理していきます。ThymeleafはSpring BootやSpring MVCと組み合わせて使われる場面が非常に多く、JavaのWebアプリケーション開発に欠かせないテンプレートエンジンです。しかし、テンプレート構文の理解不足やModelへのデータ渡し忘れ、ファイル配置ミス、フォームバリデーションエラー、フラグメントの呼び出しミスなど、初心者だけでなく実務経験者でもつまずく箇所が数多く存在します。
まず重要なのは、Thymeleafで使う変数は必ずコントローラ側でmodel.addAttributeを使って渡すという基本ルールです。Thymeleafの${}式は単純な式展開ではなく、Modelに存在するオブジェクトを参照しているため、オブジェクトを渡していない限り値は表示されません。この点が初心者に最も多いエラーポイントであり、JavaとThymeleafの橋渡しとなる要の部分です。
また、Thymeleaf特有の構文ミスとして、th:textやth:each、th:replaceといった属性の記述間違いも頻出します。特にリスト表示で用いるth:eachの「変数 : ${リスト}」という構文を忘れてしまうケースはとても多く、正しい文法を習得することがエラー解消への第一歩となります。さらにフラグメントを利用したヘッダーやフッターの共通化は便利である反面、「header :: siteHeader」のように正しい呼び出し構文で記述しないとテンプレートが正しく読み込まれず、画面が真っ白になることもあります。
Spring BootにおけるThymeleafのエラーでよくあるのが「テンプレートが存在するのに表示されない」という問題です。この場合、テンプレートの配置場所を間違えているケースがほとんどで、src/main/resources/templates 以外に置くとSpring Bootは認識しません。実務では、ファイル名を間違えたり、階層を誤った場所に移動してしまうことは珍しくなく、テンプレートの正しい位置と命名規則を理解しておくことが大切です。
さらに、フォーム入力とバリデーションに関するThymeleafエラーも非常に多く、@Valid と BindingResult のセットでの受け取り方を理解していないと、入力エラーが画面に表示されなかったり、サーバーエラーが発生したりします。Thymeleafではth:errorsや#fieldsを使ってエラーメッセージを個別に表示できるため、入力チェックの品質向上にもつながります。
これらのThymeleafエラーは、慌てずに「パスは正しいか」「Modelに渡しているか」「構文が正しいか」「キャッシュの影響はないか」といった基本チェック項目を順番に確認することでほとんど解決できます。SEO的にも「Thymeleaf エラー」「Thymeleaf 変数 null」「Thymeleaf バリデーション」「Spring Boot テンプレート 読み込まれない」「th:each エラー」「th:replace 使い方」など多くのキーワードが含まれているため、検索エンジンにも高い評価を得られるまとめとなっています。
以下に、記事内容を踏まえたThymeleafの典型的なコントローラとテンプレートの例を再掲し、理解がより深まるよう整理しておきます。
@Controller
public class SampleController {
@GetMapping("/sample")
public String showSample(Model model) {
User user = new User();
user.setName("花子");
model.addAttribute("user", user);
return "sample";
}
}
<!-- sample.html -->
<div>
<p th:text="${user.name}">名前</p>
</div>
新人:「Thymeleafのエラーって、最初は難しく見えましたが、原因が意外と基本的なところにあるって気づきました!」
先輩:「そうなんだよ。ほとんどの不具合はModelに値が渡っていないとか、構文を少し間違えているだけなんだ。順番にチェックするとすぐ原因がわかるよ。」
新人:「特にth:eachの書き方を覚えるのが大事ですね。間違えると何も表示されなくて焦ります…」
先輩:「テンプレートの配置場所も重要だね。templatesフォルダ以外に置くと絶対に表示されないから要注意だよ。」
新人:「バリデーションの@ValidとBindingResultのセットも理解できました!画面にエラーを出す仕組みって便利ですね。」
先輩:「Thymeleafが使えるようになるとSpring Boot開発の幅が一気に広がるから、これからたくさん触って慣れていこう。」