Spring MVCでは、View(ThymeleafやJSPなど)とデータを連携する場合は、org.springframework.ui.Model
インタフェースのメソッド(addAttribute
)を使います。
Note: リダイレクト時は?
ちなみに・・・リダイレクト時は
org.springframework.web.servlet.mvc.support.RedirectAttributes
インタフェースのメソッド(addFlashAttribute
)を使います。
その際に、addAttribute
やaddFlashAttribute
にCollection
オブジェクトを指定すると、どんな属性名になるか知っていますか?
答えは・・・Collection
に格納されているオブジェクトのクラス名から生成した属性名に「List
」を付与した値が、最終的な属性名になります。
Model#addAttribute
の使用
コードで見た方が誤解がないので、コードをみてみましょう
@RequestMapping(method = RequestMethod.GET)
public String list(@Validated ApiResponseSearchForm form, BindingResult result, Model model) {
if (result.hasErrors()) {
return "response/list";
}
List<ApiResponse> apiResponses =
apiResponseService.findAll(form.getPath(), form.getMethod(), form.getDescription());
model.addAttribute(apiResponses); // ← ここでModelに追加!!
return "response/list";
}
View(本投稿ではThymeleaf)からは、以下のようにデータを参照します。
<tr th:each="apiResponse : ${apiResponseList}"> <!-- ← ここでModelに追加したオブジェクトを参照!! -->
<td>
<div class="checkbox">
<label>
<input type="checkbox" name="ids" th:value="${apiResponse.id}"/>
</label>
</div>
</td>
<td>
<a class="btn btn-default" th:href="@{/manager/responses/{id}(id=${apiResponse.id})}">
<span class="glyphicon glyphicon-edit"></span>
<span th:text="#{action.edit}"></span>
</a>
</td>
<td th:text="${apiResponse.path}"></td>
<td th:text="${apiResponse.method}"></td>
<td th:text="${apiResponse.dataKey}"></td>
<td th:text="${apiResponse.statusCode}"></td>
<td th:text="${apiResponse.description}"></td>
</tr>
上の例だと、List
に格納されているクラスがApiResponse
なので、apiResponseList
が属性名になります。なお、デフォルトの属性名が気に入らない 場合は、明示的に属性名を指定することもできます!!
List<ApiResponse> apiResponses =
apiResponseService.findAll(form.getPath(), form.getMethod(), form.getDescription());
model.addAttribute("apiResponses", apiResponses); // ← 属性名を明示的に指定
Note: 配列は?
配列も
Collection
と同じ動作になります。
ちなみに・・・
クラス名から生成されるベースの属性名は、「org.springframework.core.Conventions#getVariableName(Object)
」を使って生成しているので、細い仕様はソースコード読んでください!!
@ModelAttriute
の使用
また、Model
にオブジェクトを格納する手段として@ModelAttribute
を付与したメソッドがサポートされており、こちらも同様の仕様で属性名が生成されます。こちらは、「org.springframework.core.Conventions#getVariableNameForReturnType(Method, Class<?>, Object)
」を使って生成しています。
@ModelAttribute
public List<ApiResponse> getApiResponseList() {
return apiResponseService.findAll(form.getPath(), form.getMethod(), form.getDescription());
}
こちらもデフォルトの属性名が気に入らない 場合は、明示的に属性名を指定することもできます!!
@ModelAttribute("apiResponses") // ← 属性名を明示的に指定
public List<ApiResponse> getApiResponseList() {
return apiResponseService.findAll(form.getPath(), form.getMethod(), form.getDescription());
}
要素が空の時の動作 (追記)
Model#addAttribute
やRedirectAttributes#addFlashAttribute
に指定したCollection
の要素が空の場合は、デフォルトの属性名を生成することができないためModel
の中にオブジェクトが格納されません。つまり、Viewからアクセスするとnull
として扱われる点を意識しておきましょう。Thymeleafであれば、#lists.isEmpty
メソッドを使えばnull
セーフな空判定が可能です。
<button type="button" class="btn btn-default" name="delete" data-toggle="modal"
data-target="#deleteModal" disabled="disabled"
th:if="${not #lists.isEmpty(apiResponseList)}"> <!-- ← これ -->
<span class="glyphicon glyphicon-trash"></span> 削除
</button>
まとめ
Collection
の要素が空の時の動きはちょっと注意が必要ですが・・・デフォルトの属性名を使おう!!