Thymeleafって書き方が独特でなんとなくわかりにくい。
次のプロジェクトでThymeleafを触ることになりそうなので復習がてら記事にまとめます。
Controllerのサンプル
まずはフォームを用のコントローラーを作る。
色々書いてあるがGetリクエストとPostリクエストを処理するメソッドがメイン機能。
GetはgetInit()メソッドで、PostはpostInit()メソッドで処理します。
Getメソッドはそれぞれ画面の初期処理としてチェックボックスやプルダウン用のMapを作ってmodelに詰めています。
Postメソッドは動作確認のためにリクエストで送られたパラメータをそのままセットしてGetメソッドを呼び出しています。
これでPostメソッドで送られた値がフォームに入力された状態で画面が表示されるはずです。
model.addAttributeについて
model.addAttribute()メソッドを使用するとControllerから画面に値を受け渡すことができます。
たとえば
model.addAttribute(“message”, 変数);
と記載すると画面側(thymeleaf)側でmessageという名前で変数を呼び出すことができます。
package com.example.demo.controller;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.demo.model.SampleForm;
@Controller
@RequestMapping("/sampleForm")
public class FormSampleController {
@GetMapping("/init")//①・・・Getリクエストを処理
public String getInit(Model model, SampleForm form) {
model.addAttribute("radio", getRadio());
model.addAttribute("checkBox", getCheckBox());
model.addAttribute("pulldown", getPulldown());
return "sampleForm/sampleForm";
}
@PostMapping("/post")//②・・・Postリクエストを処理
public String postInit(Model model, SampleForm form) {
return getInit(model, form);
}
/**
* ラジオボタンを作成するメソッド
* Mapでラジオボタンを作る
* @return
*/
private static Map<String, String> getRadio() {
Map<String, String> radio = new LinkedHashMap<>();
radio.put("0", "ラジオボタン0");
radio.put("1", "ラジオボタン1");
radio.put("2", "ラジオボタン2");
return radio;
}
/**
* チェックボックスを作成するメソッド
* こちらもMapで作成する
* @return
*/
private static Map<String, String> getCheckBox() {
Map<String, String> checkBox = new LinkedHashMap<>();
checkBox.put("0", "チェックボックス0");
checkBox.put("1", "チェックボックス1");
checkBox.put("2", "チェックボックス2");
return checkBox;
}
/**
* 最後にプルダウン用のMapを作成するメソッド
* @return
*/
private static Map<String, String> getPulldown() {
Map<String, String> pulldown = new LinkedHashMap<>();
pulldown.put("0", "プルダウン0");
pulldown.put("1", "プルダウン1");
pulldown.put("2", "プルダウン2");
return pulldown;
}
}
フォームのサンプル
thymeleafでよく使うフォームのサンプルを作った。
ポイントはformタグ
「th:action=”@{post}”」:ここでリクエストを送信するパスを指定する。
今回はFormSampleControllerのPostメソッドのパス”Post”を指定。
「th:object=”${sampleForm}”」の部分でフォームで送信した値をSpringBoot側でどのオブジェクトにマッピングするか指定できる。
指定の仕方はマッピングしたいクラスの頭文字を小文字にしたものを書く。
今回はSampleFormクラスにマッピングしたいので”sampleForm”と記載している。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>SampleForm</title>
</head>
<body>
<h1>SampleForm</h1>
<form th:action="@{post}" th:object="${sampleForm}" method="post">
<table>
<tr>
<th>
<label>userName</label>
</th>
<td>
<input type="text" th:field="*{userName}" />
</td>
</tr>
<tr>
<th>
<label>message</label>
</th>
<td>
<textarea rows="10" cols="80" th:field="*{message}" th:placeholder="メッセージを入力してください" >
</textarea>
</td>
</tr>
<tr>
<th>
<label>date</label>
</th>
<td>
<input type="date" th:field="*{date}" />
</td>
</tr>
<tr>
<th>
<label>radio</label>
</th>
<td>
<th:block th:each="radio:${radio}">
<label>
<input type="radio" th:text="${radio.value}"
th:value="${radio.key}"
th:field="*{radio}"
/>
</label>
</th:block>
</td>
</tr>
<tr>
<th>
<label>checkBox</label>
</th>
<td>
<label th:each="checkBox:${checkBox}">
<input type="checkbox"
th:value="${checkBox.key}"
th:text="${checkBox.value}"
th:field="*{checkBox}"
/>
</label>
</td>
</tr>
<tr>
<th>
<label>pulldown</label>
</th>
<td>
<select name="pulldown">
<option
th:each="pulldown:${pulldown}"
th:value="${pulldown.key}"
th:text="${pulldown.value}"
th:field="*{pulldown}"
>
</option>
</select>
</td>
</tr>
</table>
<input type="submit"/>
</form>
<form action="" method="get">
<button th:href="@{../}" class="button">別のページに遷移</button>
</form>
</body>
</html>
基本的なフォームの書き方
thymeleafの基本はinputタグにth:field=”{@{th:objectで指定したクラスのフィールド名}}”と書くこと。
例えば以下のように書くとPostで送信した際、Postメソッドの引数、form.userNameにテキストボックスで入力した文字が自動的にマッピングされる。
<form th:action="@{post}" th:object="${sampleForm}" method="post">
<table>
<tr>
<th>
<label>userName</label>
</th>
<td>
<input type="text" th:field="*{userName}" />
</td>
</tr>
</table>
<input type="submit"/>
</form>
@PostMapping("/post")//②・・・Postリクエストを処理
public String postInit(Model model, SampleForm form) { //ここの引数formに値が入る
System.out.println(form.getUserName); //SampleFormクラスのフィールドuserNameに
//自動でテキストボックスの内容がマッピングされる
return getInit(model, form);
th:eachの繰り返しについて
チェックボックスやプルダウンなど、フォームが複数になる場合はth:eachを使う。
ベタ書きしてしまうと変更があった際に修正箇所が膨大になってしまうから変更があっても対応可能にするためだ。
以下のコードを見てほしい。
<td>
<th:block th:each="radio:${radio}">
<label>
<input type="radio" th:text="${radio.value}"
th:value="${radio.key}"
th:field="*{radio}"
/>
</label>
</th:block>
</td>
拡張For文と同じような感覚で使えます。
th:eachでGetメソッドでmodelに詰めたradio(Map型)を指定しています。
th:each=”radio:${radio}
Map型変数のradioから要素をひとつずつ取り出してradioって名前で使うよって意味です。
以降はradioは変数と同じように使えるので${radio.フィールド名}で自由に値を使うことができます。
これでラジオボタンの選択肢を動的に生成しているというわけです。
SampleFormクラス
最後に送信されてきたフォームの値を保存するためのクラスを書いておく。
ポイントはcheckBoxが配列なこと。
checkBoxは複数選択ができ、値が複数入る場合があるから配列となっている。
lombokが入っているのでゲッター、セッターは省略している。
package com.example.demo.model;
import lombok.Data;
@Data
public class SampleForm {
private String userName;
private String message;
private String date;
private String radio;
private String[] checkBox;
private String pulldown;
}
さいごに
駆け足で書いてしまいましたが一旦ここで終わります。
何か質問などあればコメントください。
コメント