Spring Bootの@ModelAttributeとFormに値が入る仕組みを解説する記事のアイキャッチ。若手エンジニアがJava道場風の学習空間でフォーム連携を学ぶイラスト。

Spring

Spring Bootの@ModelAttributeとは?Formに値が入る仕組みと使い方

AIによる要約

@ModelAttributeは、リクエストパラメータをFormクラスへ詰めたり、画面へ渡すモデル属性として扱ったりするために使われます。Thymeleafのフォームでは、Form名、フィールド名、Controllerの引数名がずれると値が入らない原因になります。

新人SE
新人SE
Formクラスにいつ値が入っているのか、正直よく分かっていません。
ポンコツSE
ポンコツSE
@ModelAttributeは、リクエストのname属性とFormのプロパティを対応させて値を詰めます。画面側の名前とController側の名前を揃えるのが大事です。

Spring MVCの画面フォームを触ると、@ModelAttributeというアノテーションが出てきます。

サンプルでは何となく動きますが、現場で入力値が入らない、エラー時に画面へ戻れない、初期表示でFormがない、という問題がよく起きます。

この記事のポイント

  • @ModelAttributeはFormとリクエスト値を結びつける
  • GETでは空のFormを画面へ渡すことが多い
  • POSTでは入力値がFormへバインドされる
  • Form名とフィールド名のずれが値が入らない原因になる

@ModelAttributeはFormをModelに載せる

@ModelAttributeは、Formクラスを画面へ渡したり、リクエストパラメータからFormへ値を詰めたりするために使われます。

@GetMapping("/users/new")
public String newUser(Model model) {
    model.addAttribute("userRegisterForm", new UserRegisterForm());
    return "users/new";
}

GETの初期表示では、空のFormをModelに入れて画面へ渡すことが多いです。Thymeleaf側はこのFormを使って入力欄を描画します。

POSTでは入力値がFormへ入る

POST時には、画面の入力欄のnameとFormクラスのプロパティ名が対応し、値が詰められます。

@PostMapping("/users")
public String register(@ModelAttribute UserRegisterForm form) {
    userService.register(form);
    return "redirect:/users";
}

実際には@ModelAttributeを省略できる場面もありますが、初学者のうちは明示して読むと、Formに値が入る流れを理解しやすいです。

Thymeleaf側の名前が重要

画面側では、th:objectth:fieldでFormとフィールドを紐づけます。

<form th:action="@{/users}" th:object="${userRegisterForm}" method="post">
  <input type="text" th:field="*{name}">
  <input type="email" th:field="*{email}">
  <button type="submit">登録</button>
</form>

th:objectの名前とControllerでModelに入れた名前がずれると、画面表示やエラー表示でつまずきます。

値が入らないときに見るポイント

Formに値が入らないときは、Springの仕組みを疑う前に、名前の対応を確認します。

確認ポイント

  • HTMLのname属性とFormのプロパティ名が合っているか
  • th:objectの名前とModelの属性名が合っているか
  • Formクラスにsetterがあるか
  • 入力欄がdisabledになっていないか

特に、画面では表示されているのにPOSTすると値が入らない場合、name属性やth:fieldの指定ミスが多いです。

BindingResultとセットで使う

入力チェックを行う画面では、@ModelAttribute@ValidBindingResultがセットで出てきます。

@PostMapping("/users")
public String register(@Valid @ModelAttribute UserRegisterForm form,
                       BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "users/new";
    }
    userService.register(form);
    return "redirect:/users";
}

エラー時に同じ画面へ戻すことで、入力値とエラーメッセージを画面へ再表示できます。

現場では省略形にも出会う

Spring MVCでは、Formクラスの引数に@ModelAttributeが省略されているコードもあります。

@PostMapping("/users")
public String register(@Valid UserRegisterForm form,
                       BindingResult bindingResult) {
    // ...
}

省略されていても、画面フォームの入力値をFormに詰める動きは同じです。ただし、学習中やチーム内で明示した方が分かりやすい場合は、明示しても構いません。

この記事とあわせて読みたい

まとめ

@ModelAttributeは、Formクラスと画面入力をつなぐ重要な仕組みです。GETでは画面へFormを渡し、POSTでは入力値をFormへ詰める流れで理解しましょう。

値が入らないときは、難しい原因を疑う前に、Form名、フィールド名、setter、画面側のth:fieldを確認するのが現場では近道です。

-Spring
-, , , , ,