動的に生成した異なるURLに対する複数submitの実装

IDなどのパラメータを含めて動的に生成したURLにGETリクエストを送る、のPOST版をどうやって実装したらよいのかについてまとめました。

前提

最近Springの練習用にちょっとしたシステムを作成しています。
その際、よく考えず軽い気持ちで以下のような画面を設計したのですが、これをどう実装したらよいのか悩んでました。
これはデータベースから取得した雑誌の情報を一覧化し、各行にある削除ボタンを押すとその行のデータを削除する機能を持った画面です。

通常、1つのフォームに更新ボタンや削除ボタンのある画面のように複数のsubmitボタンに対応する場合、params属性にbuttonタグのname属性の値を指定した@PostMappingを付加したControllerのメソッドを複数用意することで処理を分けることができます。
しかし、動的に生成したURLの場合、生成したURLの個数分メソッドを作成しなければならず、この方法では対応できません。
そこでGETリクエストの時のようにパラメータを含めたフォーム送信先URLを複数用意し、押下したボタンに対応するURLを送信する方法を思い付き、実装できるかやってみました。

環境

  • Java: 11
  • Spring Boot: 2.3.3
  • Thymeleaf: 3.0.11

実装方法

まず、Thymeleaf側について。
HTML5ではbuttonタグにformactionという属性が用意されています。これはフォームの送信先を指定する属性です。
Thymeleafにも同様にth:formaction属性が用意されています。
他の属性についてはこちらの記事を参照してください。
[ブログ:Thymeleafで用意されている属性の一覧の一次資料]
この属性を使いURLを各ボタンに指定することで、それぞれ異なる送信先URLにリクエストを送れるようになります。

Controller側は@GetMappingの代わりに@PostMappingを指定するだけです。value属性にはGETの時と同様にURLを記載します。
また、メソッドの引数に@PathVariableを付加することでパラメータを取得できます。

実装例

Thymeleaf側で各ボタンに送信先のURLとして/list/delete/{雑誌のID}を指定し、Controller側で雑誌のIDを受け取れるようにしています。
まだ開発中なので、この例ではSTSのコンソールに取得したIDを表示するだけです。

<form method="post">
	<table>
		<!-- 省略 -->
		<tr th:each="magazine : ${magazineListForm.magazineList}">
			<!-- 省略 -->
			<td  role="presentation" sec:authorize="hasRole('ADMIN')">
				<button type="submit" th:formaction="@{'/list/delete/' + ${magazine.id}}">削除</button>
			</td>
		</tr>
	</table>
</form>
@PostMapping("/list/delete/{id}")
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public String postListDelete(Model model, @PathVariable("id") String magazineId) {
	
	System.out.println("magazineId:" + magazineId);
	
	return "redirect:/list";
}