この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: 導入方法と基本動作
SEOタイトル: Thymeleaf 導入と基本動作完全ガイド (Spring Boot 連携)

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>Thymeleaf</strong> は HTML5 と互換のテンプレートエンジン。Spring Boot で最も使われる</li><li>導入は <code>pom.xml</code> に <code>spring-boot-starter-thymeleaf</code> を追加するだけ</li><li>テンプレートは <code>src/main/resources/templates/</code> に配置 → <code>Controller</code> 戻り値の文字列でファイル名指定</li><li>HTML タグに <code>th:text</code> / <code>th:if</code> / <code>th:each</code> / <code>th:href</code> 等の属性を追加して動的化</li><li>名前空間 <code>xmlns:th="http://www.thymeleaf.org"</code> を <code><html></code> タグに宣言する (任意だが慣例)</li></ul></td></tr></table>
<h2>Thymeleaf とは</h2>

<p>Thymeleaf は HTML5 と互換のあるテンプレートエンジン。Spring Boot の標準的なビュー技術として広く使われます。最大の特徴は <strong>「ブラウザでテンプレートを直接開いてもデザインが崩れない」</strong>こと (Natural Templates) で、JSP の代替としてデファクトの座にあります。</p>

<h2>導入手順 (Spring Boot)</h2>

<h3>1. 依存関係の追加</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-xml"><!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- Spring Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency></code></pre>
<p>Gradle の場合:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-groovy">// build.gradle
dependencies {
    implementation &apos;org.springframework.boot:spring-boot-starter-thymeleaf&apos;
    implementation &apos;org.springframework.boot:spring-boot-starter-web&apos;
}</code></pre>
<h3>2. ディレクトリ構成</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">src/main/
├── java/com/example/demo/
│   ├── DemoApplication.java
│   └── HelloController.java
└── resources/
    ├── application.properties
    ├── static/
    │   └── css/style.css
    └── templates/
        ├── index.html
        └── layout/base.html</code></pre>
<h3>3. Controller</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-java">// HelloController.java
package com.example.demo;

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

@Controller
public class HelloController {

    @GetMapping("/")
    public String index(Model model) {
        model.addAttribute("name", "太郎");
        model.addAttribute("messages", List.of("こんにちは", "Hello", "Bonjour"));
        return "index";   // → src/main/resources/templates/index.html
    }
}</code></pre>
<h3>4. テンプレート (index.html)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf サンプル</title>
</head>
<body>
    <h1>こんにちは、<span th:text="${name}">ゲスト</span> さん</h1>

    <ul>
        <li th:each="msg : ${messages}" th:text="${msg}">メッセージ</li>
    </ul>
</body>
</html></code></pre>
<p>ブラウザで開くと「ゲスト」「メッセージ」と表示される (Natural Templates)。Spring Boot 経由なら動的に「太郎」「こんにちは / Hello / Bonjour」に置き換わります。</p>

<h3>5. 起動と確認</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash"># Maven
mvn spring-boot:run
# Gradle
./gradlew bootRun

# ブラウザで http://localhost:8080/ にアクセス</code></pre>
<h2>主要な Thymeleaf 属性</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>属性</th><th>用途</th><th>例</th></tr></thead>
<tbody>
<tr><td><code>th:text</code></td><td>テキスト置換 (HTML エスケープ)</td><td><code><span th:text="${name}"></span></code></td></tr>
<tr><td><code>th:utext</code></td><td>テキスト置換 (エスケープなし)</td><td><code><div th:utext="${html}"></div></code></td></tr>
<tr><td><code>th:if</code> / <code>th:unless</code></td><td>条件分岐</td><td><code><p th:if="${user.admin}">管理者</p></code></td></tr>
<tr><td><code>th:switch</code> / <code>th:case</code></td><td>switch</td><td>後述</td></tr>
<tr><td><code>th:each</code></td><td>繰り返し</td><td><code><li th:each="m : ${list}"></li></code></td></tr>
<tr><td><code>th:href</code></td><td>リンク URL</td><td><code><a th:href="@{/users/{id}(id=${u.id})}"></code></td></tr>
<tr><td><code>th:src</code></td><td>画像 URL</td><td><code><img th:src="@{/img/logo.png}"></code></td></tr>
<tr><td><code>th:action</code></td><td>フォーム action</td><td><code><form th:action="@{/login}"></code></td></tr>
<tr><td><code>th:value</code></td><td>input の値</td><td><code><input th:value="${name}"></code></td></tr>
<tr><td><code>th:field</code></td><td>フォームバインディング</td><td><code><input th:field="*{name}"></code></td></tr>
<tr><td><code>th:object</code></td><td>フォームオブジェクト</td><td><code><form th:object="${user}"></code></td></tr>
<tr><td><code>th:fragment</code></td><td>断片定義</td><td><code><div th:fragment="header"></code></td></tr>
<tr><td><code>th:insert</code> / <code>th:replace</code></td><td>断片の埋め込み</td><td><code><div th:replace="~{layout/base :: header}"></code></td></tr>
<tr><td><code>th:class</code></td><td>class 属性</td><td><code><div th:class="${active} ? 'active' : ''"></code></td></tr>
</tbody>
</table>

<h2>条件・繰り返しの例</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- if / unless -->
<p th:if="${user.admin}">管理者専用</p>
<p th:unless="${user.admin}">一般ユーザ向け</p>

<!-- switch -->
<div th:switch="${role}">
  <p th:case="&apos;admin&apos;">管理者</p>
  <p th:case="&apos;user&apos;">一般</p>
  <p th:case="*">ゲスト</p>   <!-- default -->
</div>

<!-- each + iterStat -->
<tr th:each="item, stat : ${items}">
  <td th:text="${stat.count}">1</td>     <!-- 1 始まりカウント -->
  <td th:text="${stat.index}">0</td>     <!-- 0 始まりインデックス -->
  <td th:text="${stat.size}">10</td>     <!-- 総数 -->
  <td th:text="${stat.first} ? &apos;先頭&apos; : &apos;&apos;"></td>
  <td th:text="${stat.last}  ? &apos;末尾&apos; : &apos;&apos;"></td>
  <td th:text="${item.name}"></td>
</tr></code></pre>
<h2>URL 表現 @{...}</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- 静的リソース -->
<link rel="stylesheet" th:href="@{/css/style.css}">
<img th:src="@{/img/logo.png}">

<!-- パスパラメータ -->
<a th:href="@{/users/{id}(id=${user.id})}">詳細</a>
<!-- → /users/123 -->

<!-- クエリパラメータ -->
<a th:href="@{/search(q=${keyword},page=${page})}">検索</a>
<!-- → /search?q=java&page=2 -->

<!-- 外部 URL -->
<a th:href="@{https://example.com/(ref=${ref})}">外部</a></code></pre>
<h2>レイアウト (Fragment)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- templates/layout/base.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title th:text="${title}">タイトル</title>
</head>
<body>
  <header th:fragment="header">
    <h1>サイト名</h1>
    <nav>...</nav>
  </header>

  <footer th:fragment="footer">
    <p>&copy; 2026</p>
  </footer>
</body>
</html>

<!-- templates/index.html で利用 -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
  <div th:replace="~{layout/base :: header}"></div>

  <main>
    <h2>本文</h2>
  </main>

  <div th:replace="~{layout/base :: footer}"></div>
</body>
</html></code></pre>
<h2>application.properties の設定</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-properties"># キャッシュ (開発中は false)
spring.thymeleaf.cache=false

# テンプレートディレクトリ
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

# モード (LEGACYHTML5 で XHTML 強制を緩和)
spring.thymeleaf.mode=HTML

# 文字コード
spring.thymeleaf.encoding=UTF-8

# Content-Type
spring.thymeleaf.servlet.content-type=text/html</code></pre>
<h2>FAQ</h2>

<p><strong>Q: 変更がブラウザに反映されない</strong><br />
A: <code>spring.thymeleaf.cache=false</code> + Spring Boot DevTools 導入。</p>

<p><strong>Q: テンプレートが見つからない</strong><br />
A: ファイルが <code>src/main/resources/templates/</code> 下にあるか、Controller の戻り値の文字列とファイル名が一致しているか確認。拡張子は付けない。</p>

<p><strong>Q: th:text と th:utext の使い分け</strong><br />
A: 通常は <code>th:text</code> (XSS 対策)。HTML を出力したい安全なデータだけ <code>th:utext</code>。</p>

<!-- @RESTORED_IMG_v1 -->
<h2>📸 参考画像</h2>
<p style="color:#666;font-size:0.85em;margin-bottom:1em">※ 旧バージョンから引き継いだ参考画像です。手順・図解の補助としてご覧ください。</p>
<p style="text-align:center;margin:1em 0"><img alt="参考画像" src="/uploadImage/20180727181313_8142891.png" style="max-width:640px;width:100%;height:auto;border:1px solid #ccc;border-radius:4px" /></p>