カテゴリ: Thymeleaf 更新日: 2025/11/19

Thymeleaf th:fieldの基本と便利な使い方を初心者向けに解説!

Thymeleaf th:fieldの基本と便利な使い方
Thymeleaf th:fieldの基本と便利な使い方

新人と先輩の会話形式で理解しよう

新人

「SpringでHTMLフォームを作りたいんですが、th:fieldって何のために使うんですか?」

先輩

「それはThymeleafでフォーム入力値をJavaのオブジェクトと自動でバインドするための属性だよ。とても便利なんだ。」

新人

「Javaオブジェクトに自動で? どんな風に書けばいいんですか?」

先輩

「じゃあ、HTMLフォームとth:fieldの基本から順番に説明するよ。」

1. HTMLフォームの基本とinput要素

1. HTMLフォームの基本とinput要素
1. HTMLフォームの基本とinput要素

まずはSpringとは関係なく、通常のHTMLでフォームを作る場合の基本構造を見てみましょう。以下はユーザー名とパスワードを入力するフォームの例です。


<form action="/login" method="post">
    <input type="text" name="username">
    <input type="password" name="password">
    <button type="submit">ログイン</button>
</form>

このようにinputタグのname属性を使って、サーバー側にデータを送信します。ただし、Springでフォームバインドを使いたい場合は、これだけでは不十分です。コントローラ側で受け取るモデルオブジェクトと連携するためには、Thymeleafのth:objectth:fieldを使う必要があります。

2. Thymeleafのth:fieldとは?(フォームとの連携)

2. Thymeleafのth:fieldとは?(フォームとの連携)
2. Thymeleafのth:fieldとは?(フォームとの連携)

Thymeleafにおけるth:field属性は、Spring MVCのフォームバインド機能と連携して、HTMLフォームの各フィールドをJavaのオブジェクトと結びつけるために使います。

例えば、以下のようなUserFormクラスがあるとします。


public class UserForm {
    private String username;
    private String password;

    // getterとsetterは省略
}

このUserFormを使って、コントローラでは以下のようにモデルに登録します。


@Controller
public class LoginController {

    @GetMapping("/login")
    public String showLoginForm(Model model) {
        model.addAttribute("userForm", new UserForm());
        return "login";
    }

    @PostMapping("/login")
    public String submitLogin(@ModelAttribute UserForm userForm) {
        // ログイン処理
        return "result";
    }
}

この場合、Thymeleafのテンプレートでは次のようにth:objectth:fieldを使います。


<form th:action="@{/login}" th:object="${userForm}" method="post">
    <input type="text" th:field="*{username}" />
    <input type="password" th:field="*{password}" />
    <button type="submit">ログイン</button>
</form>

th:objectでバインド対象のオブジェクトを指定し、th:fieldでオブジェクトのフィールド名を指定します。*{username}と書くことで、userForm.getUsername()のように連携してくれるのです。

初心者が混乱しやすいポイントとして、th:fieldを使うと、自動的にname属性やid属性も自動で生成されます。そのため、手動でnameを指定する必要はありません。

補足:HTMLに出力される実際のコード

上記のth:fieldを使ったフォームは、ブラウザに表示されると以下のようなHTMLに変換されます。


<form action="/login" method="post">
    <input type="text" id="username" name="username" value="">
    <input type="password" id="password" name="password" value="">
    <button type="submit">ログイン</button>
</form>

このように、th:fieldを使うことで、idnamevalueなどの属性を自動でバインドしてくれるため、記述ミスを防げて非常に便利です。

ラジオボタンやチェックボックスの場合

th:fieldは、テキスト入力だけでなく、ラジオボタンやチェックボックスにも使えます。


<label><input type="radio" th:field="*{gender}" value="male"> 男性</label>
<label><input type="radio" th:field="*{gender}" value="female"> 女性</label>

<label><input type="checkbox" th:field="*{agree}"> 利用規約に同意する</label>

ラジオボタンでは同じフィールド名に対して異なるvalueを持たせることで、1つだけ選択されるようになります。チェックボックスではboolean型のフィールドと連携することで、オン・オフの状態を管理できます。

select要素(プルダウン)との連携

selectタグにもth:fieldを使うことができます。以下は都道府県の一覧を選択肢として表示する例です。


<select th:field="*{prefecture}">
    <option value="tokyo">東京都</option>
    <option value="osaka">大阪府</option>
    <option value="hokkaido">北海道</option>
</select>

コントローラ側でuserForm.setPrefecture("osaka")のようにしておけば、「大阪府」が初期選択されます。

3. th:fieldを使ったバインドの具体例(オブジェクトとの連携)

3. th:fieldを使ったバインドの具体例(オブジェクトとの連携)
3. th:fieldを使ったバインドの具体例(オブジェクトとの連携)

ここでは、Thymeleafのth:fieldを使って、複数のフィールドを含むフォーム入力をオブジェクトにバインドする具体的な例を紹介します。初心者向けに、エンティティクラスとテンプレート、そしてコントローラの流れを丁寧に見ていきましょう。

まずはユーザー登録用のフォームオブジェクトを定義します。


public class RegisterForm {
    private String name;
    private String email;
    private int age;
    private String password;

    // getterとsetterは省略
}

次にコントローラ側でこのフォームをモデルに追加します。


@Controller
public class RegisterController {

    @GetMapping("/register")
    public String showForm(Model model) {
        model.addAttribute("registerForm", new RegisterForm());
        return "register";
    }

    @PostMapping("/register")
    public String submitForm(@ModelAttribute RegisterForm registerForm) {
        // 登録処理を行う
        return "result";
    }
}

そして、Thymeleafテンプレートでは以下のようにth:objectth:fieldを活用して、オブジェクトとフォーム入力を連携させます。


<form th:action="@{/register}" th:object="${registerForm}" method="post">
    <label>名前: <input type="text" th:field="*{name}"></label><br>
    <label>メール: <input type="email" th:field="*{email}"></label><br>
    <label>年齢: <input type="number" th:field="*{age}"></label><br>
    <label>パスワード: <input type="password" th:field="*{password}"></label><br>
    <button type="submit">登録</button>
</form>

このようにth:fieldを使用することで、オブジェクトのフィールドとフォームの値が自動的に結びつきます。初心者が混乱しやすい点としては、th:objectとセットで使わないとth:fieldが正しく動作しないことがあります。この点に注意してください。

4. 入力値の保持とエラーメッセージの表示

4. 入力値の保持とエラーメッセージの表示
4. 入力値の保持とエラーメッセージの表示

フォームで入力された値にエラーがあった場合、そのまま再表示して入力値を保持したり、エラーメッセージを表示するのもThymeleafでは簡単に行えます。ここでは@ValidBindingResultを使った例を紹介します。

まず、フォームクラスにバリデーションアノテーションを追加します。


public class RegisterForm {

    @NotBlank(message = "名前を入力してください")
    private String name;

    @Email(message = "正しいメールアドレスを入力してください")
    private String email;

    @Min(value = 18, message = "18歳以上で登録できます")
    private int age;

    @Size(min = 6, message = "パスワードは6文字以上で入力してください")
    private String password;

    // getterとsetterは省略
}

コントローラでは次のように@ValidBindingResultをセットで使います。


@PostMapping("/register")
public String submitForm(@Valid @ModelAttribute RegisterForm registerForm, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "register";
    }
    // 成功時の処理
    return "result";
}

Thymeleafテンプレートでエラーを表示するには、th:errorsを使います。以下のようにフィールドごとにエラーを表示できます。


<form th:action="@{/register}" th:object="${registerForm}" method="post">
    <label>名前: <input type="text" th:field="*{name}"></label>
    <div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>

    <label>メール: <input type="email" th:field="*{email}"></label>
    <div th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>

    <label>年齢: <input type="number" th:field="*{age}"></label>
    <div th:if="${#fields.hasErrors('age')}" th:errors="*{age}"></div>

    <label>パスワード: <input type="password" th:field="*{password}"></label>
    <div th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></div>

    <button type="submit">登録</button>
</form>

このようにすると、フォーム入力時にバリデーションエラーがあった場合でも、入力値は保持され、該当フィールドの直下にエラーメッセージが表示されます。初心者が間違いやすい点としては、BindingResultの位置が@ModelAttributeの直後でないと無効になることです。注意しましょう。

5. th:fieldで扱えるフォーム部品(input、textarea、selectなど)

5. th:fieldで扱えるフォーム部品(input、textarea、selectなど)
5. th:fieldで扱えるフォーム部品(input、textarea、selectなど)

Thymeleafのth:field属性は、さまざまな種類のフォーム部品で使うことができます。ここでは初心者向けに、よく使われる代表的なフォーム要素との組み合わせを紹介します。

テキストエリア(textarea

複数行のテキスト入力にはtextareaを使いますが、Thymeleafでもth:fieldを使ってバインドできます。


<label>自己紹介:</label>
<textarea th:field="*{introduction}"></textarea>

これにより、入力された内容がJavaのオブジェクトと連携され、再表示時にも内容が保持されます。

セレクトボックス(select

select要素とth:fieldを組み合わせることで、リストから選択された値を自動でバインドできます。


<select th:field="*{job}">
    <option value="engineer">エンジニア</option>
    <option value="designer">デザイナー</option>
    <option value="manager">マネージャー</option>
</select>

選択肢の値は、Javaオブジェクトのフィールドに対応する値として渡されます。

チェックボックスとラジオボタン

チェックボックスとラジオボタンも、th:fieldで簡単に使えます。


<label><input type="checkbox" th:field="*{subscribe}"> メール配信を希望する</label>

<label><input type="radio" th:field="*{gender}" value="male"> 男性</label>
<label><input type="radio" th:field="*{gender}" value="female"> 女性</label>

チェックボックスの場合、バインド先はboolean型のフィールドとなり、チェックの有無で値が変わります。ラジオボタンは同じth:fieldで複数の選択肢を表示する形式になります。

このように、th:fieldはフォーム入力に必要な主要な部品すべてに対応しており、初心者でも簡単にオブジェクトとのデータ連携を実現できます。

6. よくあるバインドエラーとth:fieldの注意点(nullや型不一致など)

6. よくあるバインドエラーとth:fieldの注意点(nullや型不一致など)
6. よくあるバインドエラーとth:fieldの注意点(nullや型不一致など)

初心者がThymeleafのth:fieldを使ってフォームバインドを行うとき、最もつまずきやすいのが「バインド エラー」です。特に、nullの取り扱いや型の不一致によるエラーは頻出で、エラー画面に赤いスタックトレースが表示されて驚いてしまうこともあります。

たとえば、フォームクラスで次のような定義をしているとします。


public class UserForm {
    private int age;
    // getter/setter省略
}

このとき、ageが数値ではなく空欄のまま送信された場合、Springはint型にnullを入れることができず、バインド エラーになります。これを避けるには、ラッパークラスであるInteger型を使うようにしましょう。


private Integer age;

また、フォームの値を受け取るときに、Thymeleafテンプレート上で指定しているフィールド名が実際のJavaクラスに存在しない場合も、th:fieldは正しく機能せず、空のフォームや例外の原因になります。

このようなケースに備えて、th:fieldを記述する際は、バインド対象のフィールド名とJava側のプロパティ名が一致しているかラッパークラスを使ってnull対応しているかを常に確認する習慣をつけておきましょう。

7. 実務で役立つth:fieldの応用例(リストやネスト構造への対応)

7. 実務で役立つth:fieldの応用例(リストやネスト構造への対応)
7. 実務で役立つth:fieldの応用例(リストやネスト構造への対応)

実際の業務では、単純な文字列や数値の入力だけでなく、「リスト形式の入力」や「ネストしたオブジェクト」へのフォームバインドが求められるケースがよくあります。Thymeleafのth:fieldは、こうした複雑な構造にも対応できます。

リスト構造とのバインド

たとえば、複数の電話番号を入力するような場面を考えてみましょう。


public class ContactForm {
    private List<String> phones;
    // getter/setter省略
}

このとき、Thymeleafテンプレートではインデックス番号を使ってth:fieldを指定します。


<form th:action="@{/contact}" th:object="${contactForm}" method="post">
    <input type="text" th:field="*{phones[0]}" placeholder="電話番号1"><br>
    <input type="text" th:field="*{phones[1]}" placeholder="電話番号2"><br>
    <button type="submit">送信</button>
</form>

このように書くことで、phonesリストの0番目、1番目の要素にそれぞれバインドされます。フォーム側で空のリストが送られてくることもあるので、コントローラでは初期化しておくと安全です。


model.addAttribute("contactForm", new ContactForm(List.of("", "")));

ネストしたオブジェクトへのバインド

次に、親オブジェクトの中に別のオブジェクトを持つ「ネスト構造」の例を見てみましょう。


public class EmployeeForm {
    private String name;
    private Department department;
    // getter/setter省略
}

public class Department {
    private String code;
    private String name;
    // getter/setter省略
}

このような場合、Thymeleafではドット記法でth:fieldを指定します。


<form th:action="@{/employee}" th:object="${employeeForm}" method="post">
    <label>社員名: <input type="text" th:field="*{name}"></label><br>
    <label>部署コード: <input type="text" th:field="*{department.code}"></label><br>
    <label>部署名: <input type="text" th:field="*{department.name}"></label><br>
    <button type="submit">登録</button>
</form>

このように、th:fieldはリストやネスト構造にも柔軟に対応できるため、実務でも非常に役立ちます。初心者が注意すべき点は、ネストしたオブジェクトのインスタンスがnullのままだとバインド時に例外が発生するため、コントローラで必ず初期化しておく必要があることです。

8. フォーム送信とコントローラの連携(POSTの受け取り、ModelAttributeなど)

8. フォーム送信とコントローラの連携(POSTの受け取り、ModelAttributeなど)
8. フォーム送信とコントローラの連携(POSTの受け取り、ModelAttributeなど)

最後に、フォーム送信後にth:fieldでバインドされた値を、Springの@Controllerクラスでどのように受け取るかについて説明します。フォームとコントローラの連携は、初心者がつまずきやすいポイントなので、順を追って丁寧に解説します。

まず、Thymeleaf側のフォームにはth:actionmethod="post"を設定し、th:objectでバインド対象のオブジェクトを指定します。


<form th:action="@{/submit}" th:object="${userForm}" method="post">
    <input type="text" th:field="*{username}">
    <input type="password" th:field="*{password}">
    <button type="submit">送信</button>
</form>

次に、コントローラ側では@PostMappingで送信先を受け取り、@ModelAttributeを使ってフォームオブジェクトをバインドします。


@Controller
public class UserController {

    @PostMapping("/submit")
    public String handleForm(@ModelAttribute UserForm userForm) {
        // userForm.getUsername()やgetPassword()で値を取得できる
        return "result";
    }
}

ここで重要なのが、Thymeleafのテンプレートで使っているモデル名(例:userForm)と、コントローラで受け取る@ModelAttributeの型が一致していることです。

さらに、バリデーションを使う場合は@ValidBindingResultを組み合わせることで、エラーメッセージの表示や再描画にも対応できます。


@PostMapping("/submit")
public String handleForm(@Valid @ModelAttribute UserForm userForm, BindingResult result) {
    if (result.hasErrors()) {
        return "form"; // エラーがある場合は元のフォームに戻る
    }
    return "result"; // 正常なら次の画面へ
}

このように、Thymeleafのth:fieldでフォーム入力とJavaオブジェクトをバインドし、コントローラの@ModelAttributeで値を受け取る流れは、Spring MVCの基本的な連携パターンです。

初心者が間違えやすいのは、th:objectを使わずにth:fieldだけを使ってしまい、意図したバインドがされないというケースです。正しくオブジェクトと連携させるためにも、テンプレート・モデル・コントローラの対応を意識しておきましょう。

コメント
コメント投稿は、ログインしてください

まだ口コミはありません。

カテゴリの一覧へ
新着記事
New1
SpringのWeb開発(Spring MVC)
HTTPリクエストとレスポンスの基本を完全解説!Spring MVC初心者がWeb通信の仕組みをやさしく理解
New2
Spring認証(Spring Security)
ブラウザからのフォーム送信とは?HTTPリクエストの基礎を初心者向けに解説!
New3
Thymeleaf
ThymeleafでJavaScriptコメントを正しく書こう!初心者向け徹底解説
New4
SpringのDB操作
Spring Boot + MySQLでCRUDアプリを作ろう!初心者向けにデータベース操作を完全解説
人気記事
No.1
Java&Spring記事人気No1
SpringのWeb開発(Spring MVC)
ルーティングとは?基本概念(Spring MVCのURL制御を理解)
No.2
Java&Spring記事人気No2
Thymeleaf
Thymeleaf とは?初心者向けにThymeleafの基本を徹底解説
No.3
Java&Spring記事人気No3
Springの基本
application.properties と YAML の基本をやさしく解説!初心者向けSpring Boot設定ファイル入門
No.4
Java&Spring記事人気No4
Springの基本
Spring Bootの環境変数の設定方法をやさしく解説!初心者向けapplication.propertiesの使い方
No.5
Java&Spring記事人気No5
Springの基本
Spring Bootのデフォルトログ設定を徹底解説(Logback / SLF4J)
No.6
Java&Spring記事人気No6
SpringのWeb開発(Spring MVC)
ループ処理(th:each)の基本を完全ガイド!Thymeafの繰り返し処理の使い方
No.7
Java&Spring記事人気No7
SpringのDB操作
JPAの標準クエリメソッド(findById, findAll)を完全解説!初心者でもわかるデータ取得の基本
No.8
Java&Spring記事人気No8
SpringのDB操作
@Queryを使ったカスタムクエリの作成を完全解説!Spring Data JPAでの使い方と基礎知識