はじめに
controllerの引数@PathVariableでURLから受けとったプロパティを、
thymeleafで表示させる際の挙動について備忘録
※間違い等あればご指摘いただけますと幸いです。
環境
・JavaSE 17
・springframework 3.3.1
・PostgreSQL 12.17
・MacOS 13.1
本題
idとnameからなる「カテゴリー」を登録・更新するformを作成する。
今回は更新の場合について注目。
カテゴリーの一覧画面から編集ボタンを押し、更新formを表示する流れを想定。
更新formには初期値として更新対象のid(readonly)とnameをinputエリアに表示させる。
※controllerとhtml部分のみ抜粋。
CategoryController.java
@Controller
@RequestMapping("/category")
public class CategoryController {
@Autowired
CategoryService categoryService;
@ModelAttribute
public CategoryForm setUpForm() {
CategoryForm categoryForm = new CategoryForm();
return categoryForm;
}
// 中略
// 編集ページ表示用
@GetMapping("/{id}")
private String showOneCategoryById(@PathVariable Integer id,
CategoryForm categoryForm, Model model) {
categoryForm.setNewCategory(false);
Optional<Category> categoryOpt = categoryService.selectOneById(id);
if(categoryOpt.isPresent()) {
Category category = categoryOpt.get();
categoryForm.setId(category.getId());
categoryForm.setName(category.getName());
}
model.addAttribute("categoryForm", categoryForm);
return "categoryPage";
}
説明:
編集ボタンを押した際、URLパスに対象のidを設定、/category/{対象のid}にリクエストを送信、controllerのshowOneCategoryByIdで受ける。
@PathVariable Integer idでURLパスからidを取得。
idを条件にDBからレコードを取得し、CategoryクラスからCategoryFormクラスに詰め替えを行う。
model.addAttributeでcategoryFormオブジェクトをモデルに追加し、ビューに渡している。
categoryPage.html(一部抜粋)
<div>
<p th:if="${complete}" style="color: orange">[[${complte}]]</p>
<form method="post"
th:action="${newCategory}? @{/category/insert} :@{/category/update}" th:object="${categoryForm}">
<label>ID:</label><br>
<input th:if="${id}" readonly th:field="*{id}"><br>
<label>カテゴリー名:</label><br>
<input type="text" th:field="*{name}">
<button type="submit">登録</button>
</form>
</div>
※新規登録と編集で共用のフォームになっているため、idは値がある場合=更新の場合のみしか表示させない仕様。
渡されたcategoryFormから、{id}、{name}でそれぞれの値を取り出し、inputエリアに初期値として表示させている。
ふとここで疑問に思った。
idをmodel.addAttributeしていないのにth:if="${id}"が機能しているのはなぜだ・・・?と。
答えは下記にあった。
CategoryController.java
@ModelAttribute
public CategoryForm setUpForm() {
CategoryForm categoryForm = new CategoryForm();
return categoryForm;
}
// 編集ページ表示用
@GetMapping("/{id}")
private String showOneCategoryById(@PathVariable Integer id,
CategoryForm categoryForm, Model model){
まず、@ModelAttributeでコントローラメソッドの引数で使用するフォームオブジェクトは自動的にモデルに追加される。
@PathVariableで受け取ったidは自動でmodelとcategoryFormにセットされる。
そのため、明示的にmodel.addAttribute("id", id)しなくても、thymeleafで${id}でアクセスすることができる。
また、上記により、
idは引数内でcategoryFormにセットされているため、model.addAttribute("categoryForm", categoryForm)しなくても
th:field="*{id}"でアクセスできるが、
nameはリクエストハンドラメソッド内で取得したパラメータなので、
model.addAttribute("categoryForm", categoryForm)しないと、
th:field="*{name}"でアクセスすることができない。
以上です。