1. 概要

最も重要なSpringMVC アノテーションの1つは、@ModelAttributeアノテーションです。

@ModelAttribute は、メソッドパラメーターまたはメソッド戻り値を名前付きモデル属性にバインドし、それをWebビューに公開するアノテーションです。

このチュートリアルでは、会社の従業員から送信されたフォームである一般的な概念を通じて、この注釈の使いやすさと機能性を示します。

2. @ModelAttribute in Depth

導入段落で明らかにしたように、@ModelAttributeをメソッドパラメーターまたはメソッドレベルで使用できます。

2.1. メソッドレベルで

メソッドレベルでアノテーションを使用する場合、メソッドの目的が1つ以上のモデル属性を追加することであることを示します。 このようなメソッドは、 @RequestMapping メソッドと同じ引数タイプをサポートしますが、リクエストに直接マッピングすることはできません。

これがどのように機能するかを理解するために、ここで簡単な例を見てみましょう。

@ModelAttribute
public void addAttributes(Model model) {
    model.addAttribute("msg", "Welcome to the Netherlands!");
}

上記の例では、コントローラークラスで定義されているすべてのmodelmsgという名前の属性を追加するメソッドが表示されています。

もちろん、これはこの記事の後半で実際に動作することを確認します。

一般に、Spring MVCは、要求ハンドラーメソッドを呼び出す前に、常に最初にそのメソッドを呼び出します。 基本的に、 @ModelAttributeメソッドは、@ RequestMappingで注釈が付けられたコントローラーメソッドが呼び出される前に呼び出されます。これは、コントローラーメソッド内で処理を開始する前にモデルオブジェクトを作成する必要があるためです。

それぞれのクラスに@ControllerAdviceという注釈を付けることも重要です。 したがって、グローバルとして識別されるModelに値を追加できます。 これは、実際には、すべての要求に対して、応答のすべてのメソッドにデフォルト値が存在することを意味します。

2.2. メソッド引数として

メソッド引数としてアノテーションを使用すると、モデルから引数を取得することを示します。 注釈が存在しない場合は、最初にインスタンス化してから、モデルに追加する必要があります。 モデルに存在すると、引数フィールドは、名前が一致するすべてのリクエストパラメータから入力する必要があります。

次のコードスニペットでは、 employee モデル属性に、addEmployeeエンドポイントに送信されたフォームからのデータを入力します。 Spring MVCは、submitメソッドを呼び出す前に、これをバックグラウンドで実行します。

@RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
public String submit(@ModelAttribute("employee") Employee employee) {
    // Code that uses the employee object

    return "employeeView";
}

この記事の後半で、employeeオブジェクトを使用してemployeeViewテンプレートにデータを入力する方法の完全な例を示します。

フォームデータをBeanにバインドします。 @RequestMappingで注釈が付けられたコントローラーは、@ModelAttributeで注釈が付けられたカスタムクラス引数を持つことができます。

Spring MVCでは、これをデータバインディングと呼びます。これは、各フォームフィールドを個別に解析する必要がない一般的なメカニズムです。

3. フォームの例

このセクションでは、概要セクションで概説されている例を見ていきます。これは、ユーザー(具体的には会社の従業員)に個人情報(具体的には名前 id)。 送信が完了した後、エラーが発生しない場合、ユーザーは以前に送信されたデータが別の画面に表示されることを期待しています。

3.1. 景色

まず、idフィールドとnameフィールドを使用して単純なフォームを作成しましょう。

<form:form method="POST" action="/spring-mvc-basics/addEmployee" 
  modelAttribute="employee">
    <form:label path="name">Name</form:label>
    <form:input path="name" />
    
    <form:label path="id">Id</form:label>
    <form:input path="id" />
    
    <input type="submit" value="Submit" />
</form:form>

3.2. コントローラー

これがコントローラークラスで、前述のビューのロジックを実装します。

@Controller
@ControllerAdvice
public class EmployeeController {

    private Map<Long, Employee> employeeMap = new HashMap<>();

    @RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
    public String submit(
      @ModelAttribute("employee") Employee employee,
      BindingResult result, ModelMap model) {
        if (result.hasErrors()) {
            return "error";
        }
        model.addAttribute("name", employee.getName());
        model.addAttribute("id", employee.getId());

        employeeMap.put(employee.getId(), employee);

        return "employeeView";
    }

    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("msg", "Welcome to the Netherlands!");
    }
}

submit()メソッドには、ViewにバインドされたEmployeeオブジェクトがあります。 フォームフィールドをオブジェクトモデルにマッピングするのは、それと同じくらい簡単です。 このメソッドでは、フォームから値を取得し、それらをModelMapに設定しています。

最後に、 employeeView を返します。これは、それぞれのJSPファイルをViewの代表として呼び出すことを意味します。

さらに、 addAttributes()メソッドもあります。 その目的は、グローバルに識別されるモデルに値を追加することです。 つまり、すべてのコントローラーメソッドへのすべての要求は、応答としてデフォルト値を返します。 また、特定のクラスに@ControllerAdvice。という注釈を付ける必要があります。

3.3. モデル

前述のように、 Model オブジェクトは非常に単純で、「フロントエンド」属性に必要なものがすべて含まれています。 次に、例を見てみましょう。

@XmlRootElement
public class Employee {

    private long id;
    private String name;

    public Employee(long id, String name) {
        this.id = id;
        this.name = name;
    }

    // standard getters and setters removed
}

3.4. 要約

@ControllerAdvice は、コントローラー、特にすべての@RequestMappingメソッドに適用される@ModelAttributeメソッドを支援します。 もちろん、 addAttributes()メソッドは、残りの @RequestMapping メソッドの前に、最初に実行されます。

そのことを念頭に置いて、 submit() addAttributes()の両方を実行した後、から返されたViewでそれらを参照できます。 Controller クラスは、 $ {name} のように、ドル化された中括弧のデュオ内で名前を指定します。

3.5. 結果ビュー

次に、フォームから受け取ったものを印刷しましょう。

<h3>${msg}</h3>
Name : ${name}
ID : ${id}

4. 結論

この記事では、メソッド引数とメソッドレベルのユースケースの両方で@ModelAttributeアノテーションの使用を調査しました。

この記事の実装は、githubプロジェクトにあります。