これまでこのブログで記載してきたSpring Bootアプリケーションのソースコードは、コードリストの値をFormクラスに記載していたが、FormクラスやControllerクラスを経由しなくても、Springのコンテキスト管理下にあるコードリストの値をThymeleafで直接参照することができる。
今回は、Formクラスに記載していたコードリストの値をThymeleafで直接参照するようにしてみたので、そのサンプルプログラムを共有する。
前提条件
下記記事の実装が完了していること。
サンプルプログラムの構成
作成したサンプルプログラムの構成は以下の通り。
なお、上記の赤枠は、前提条件のプログラムから今回追加・変更したプログラムである。
DemoCodeMapクラスの内容は以下の通りで、DemoFormクラス・SearchFormクラスに記載していたコードリストの内容を、Springのコンテキスト管理下に記載している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.example.demo; import org.springframework.stereotype.Repository; import java.util.LinkedHashMap; import java.util.Map; @Repository("demoCodeMap") public class DemoCodeMap { /** 生年月日_月のMapオブジェクト */ public Map<String,String> getMonthItems(){ Map<String, String> monthMap = new LinkedHashMap<String, String>(); for(int i = 1; i <= 12; i++){ monthMap.put(String.valueOf(i), String.valueOf(i)); } return monthMap; } /** 生年月日_日のMapオブジェクト */ public Map<String,String> getDayItems(){ Map<String, String> dayMap = new LinkedHashMap<String, String>(); for(int i = 1; i <= 31; i++){ dayMap.put(String.valueOf(i), String.valueOf(i)); } return dayMap; } /** 性別のMapオブジェクト */ public Map<String,String> getSexItems(){ Map<String, String> sexMap = new LinkedHashMap<String, String>(); sexMap.put("1", "男"); sexMap.put("2", "女"); return sexMap; } } |
DemoFormクラス・SearchFormクラスの内容は以下の通りで、DemoCodeMapクラスに記載したコードリストを削除している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | package com.example.demo; import com.example.demo.check.CheckDate; import com.example.demo.check.CheckZenkaku; import com.example.demo.check.FutureDate; import lombok.Data; import org.thymeleaf.util.StringUtils; import javax.validation.constraints.AssertTrue; import javax.validation.constraints.NotEmpty; import java.io.Serializable; //日付チェック・未来日チェックを独自アノテーションで実施 @Data @CheckDate(dtYear = "birthYear", dtMonth = "birthMonth", dtDay = "birthDay" , message = "{validation.date-invalidate}") @FutureDate(dtYear = "birthYear", dtMonth = "birthMonth", dtDay = "birthDay" , message = "{validation.date-future}") public class DemoForm implements Serializable { /** ID */ private String id; /** 名前 */ @NotEmpty @CheckZenkaku private String name; /** 生年月日_年 */ private String birthYear; /** 生年月日_月 */ private String birthMonth; /** 生年月日_日 */ private String birthDay; /** 性別 */ @NotEmpty private String sex; /** メモ */ private String memo; /** 確認チェック */ @NotEmpty private String checked; /** 性別(文字列) */ private String sex_value; /** * 生年月日の年・月・日が入力されているかをチェックする * @return チェック結果 */ @AssertTrue(message = "{validation.date-empty}") public boolean isBirthDayRequired(){ if(StringUtils.isEmpty(birthYear) && StringUtils.isEmpty(birthMonth) && StringUtils.isEmpty(birthDay)){ return false; } return true; } /** * 性別が不正な値でないかチェックする * @return チェック結果 */ @AssertTrue(message = "{validation.sex-invalidate}") public boolean isSexInvalid(){ return StringUtils.isEmpty(sex) || new DemoCodeMap().getSexItems().keySet().contains(sex); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.example.demo; import com.example.demo.check.CheckDate; import com.example.demo.check.CheckFromToDate; import lombok.Data; //生年月日_from,toの日付チェックを独自アノテーションで実施 @Data @CheckDate(dtYear = "fromBirthYear", dtMonth = "fromBirthMonth" , dtDay = "fromBirthDay", message = "{validation.date-invalidate-from}") @CheckDate(dtYear = "toBirthYear", dtMonth = "toBirthMonth" , dtDay = "toBirthDay", message = "{validation.date-invalidate-to}") @CheckFromToDate(dtYearFrom = "fromBirthYear", dtMonthFrom = "fromBirthMonth" , dtDayFrom = "fromBirthDay", dtYearTo = "toBirthYear" , dtMonthTo = "toBirthMonth", dtDayTo = "toBirthDay" , message = "{validation.date-invalidate-from-to}") public class SearchForm { /** 検索用名前 */ private String searchName; /** 生年月日_年_from */ private String fromBirthYear; /** 生年月日_月_from */ private String fromBirthMonth; /** 生年月日_日_from */ private String fromBirthDay; /** 生年月日_年_to */ private String toBirthYear; /** 生年月日_月_to */ private String toBirthMonth; /** 生年月日_日_to */ private String toBirthDay; /** 検索用性別 */ private String searchSex; /** 一覧画面の現在ページ数 */ private int currentPageNum; } |
検索画面(search.html)の内容は以下の通りで、例えば「*{getMonthItems()}」と記載していた箇所を、「${@demoCodeMap.getMonthItems()}」と修正している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | <!DOCTYPE html> <html lang="jp" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <link th:href="@{/demo.css}" rel="stylesheet" type="text/css" /> <title>index page</title> </head> <body> <p>検索条件を指定し、「検索」ボタンを押下してください。</p><br/> <form method="post" th:action="@{/search}" th:object="${searchForm}"> <!-- 2行エラーがある場合は、エラーメッセージを改行して表示 --> <span th:if="*{#fields.hasErrors('fromBirthYear')}" th:errors="*{fromBirthYear}" class="errorMessage"></span> <span th:if="*{#fields.hasErrors('fromBirthYear') " + "&& #fields.hasErrors('toBirthYear')}"> <br/> </span> <span th:if="*{#fields.hasErrors('toBirthYear')}" th:errors="*{toBirthYear}" class="errorMessage"></span> <table border="1" cellpadding="5"> <tr> <th>名前</th> <td><input type="text" th:value="*{searchName}" th:field="*{searchName}" /></td> </tr> <tr> <th>生年月日</th> <td><input type="text" th:value="*{fromBirthYear}" size="4" maxlength="4" th:field="*{fromBirthYear}" th:errorclass="fieldError"/>年 <select th:field="*{fromBirthMonth}" th:errorclass="fieldError" th:classappend="${#fields.hasErrors('fromBirthYear')} " + "? 'fieldError'"> <option value=""></option> <option th:each="item : ${@demoCodeMap.getMonthItems()}" th:value="${item.key}" th:text="${item.value}" /> </select>月 <select th:field="*{fromBirthDay}" th:errorclass="fieldError" th:classappend="${#fields.hasErrors('fromBirthYear')} " + "? 'fieldError'"> <option value=""></option> <option th:each="item : ${@demoCodeMap.getDayItems()}" th:value="${item.key}" th:text="${item.value}" /> </select>日~ <input type="text" th:value="*{toBirthYear}" size="4" maxlength="4" th:field="*{toBirthYear}" th:errorclass="fieldError"/>年 <select th:field="*{toBirthMonth}" th:errorclass="fieldError" th:classappend="${#fields.hasErrors('toBirthYear')} " + "? 'fieldError'"> <option value=""></option> <option th:each="item : ${@demoCodeMap.getMonthItems()}" th:value="${item.key}" th:text="${item.value}" /> </select>月 <select th:field="*{toBirthDay}" th:errorclass="fieldError" th:classappend="${#fields.hasErrors('toBirthYear')} " + "? 'fieldError'"> <option value=""></option> <option th:each="item : ${@demoCodeMap.getDayItems()}" th:value="${item.key}" th:text="${item.value}" /> </select>日 </td> </tr> <tr> <th>性別</th> <td> <select th:field="*{searchSex}"> <option value=""></option> <option th:each="item : ${@demoCodeMap.getSexItems()}" th:value="${item.key}" th:text="${item.value}" /> </select> </td> </tr> </table> <br/><br/> <input type="submit" value="検索" /><br/><br/> <input type="button" value="閉じる" onclick="window.close();" /> </form> </body> </html> |
入力画面(input.html)・確認画面(confirm.html)・削除確認画面(confirm_delete.html)の内容は以下の通りで、検索画面と同じ修正を行っている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | <!DOCTYPE html> <html lang="jp" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <link th:href="@{/demo.css}" rel="stylesheet" type="text/css" /> <title>入力画面</title> </head> <body> <p>下記必要事項を記載の上、「確認」ボタンを押下してください。</p><br/> <form method="post" th:action="@{/confirm}" th:object="${demoForm}"> <table border="0"> <tr> <td align="left" valign="top">名前:</td> <td> <input type="text" th:value="*{name}" th:field="*{name}" th:errorclass="fieldError" /> <span th:if="*{#fields.hasErrors('name')}" th:errors="*{name}" class="errorMessage"></span> </td> </tr> <tr> <td align="left" valign="top">生年月日:</td> <td> <input type="text" th:value="*{birthYear}" size="4" maxlength="4" th:field="*{birthYear}" th:errorclass="fieldError" th:classappend="${#fields.hasErrors('birthDayRequired')} " + "? 'fieldError'" />年 <select th:field="*{birthMonth}" th:errorclass="fieldError" th:classappend="${#fields.hasErrors('birthYear') || #fields.hasErrors('birthDayRequired')} " + "? 'fieldError'"> <option value="">---</option> <option th:each="item : ${@demoCodeMap.getMonthItems()}" th:value="${item.key}" th:text="${item.value}" /> </select>月 <select th:field="*{birthDay}" th:errorclass="fieldError" th:classappend="${#fields.hasErrors('birthYear') || #fields.hasErrors('birthDayRequired')} " + "? 'fieldError'"> <option value="">---</option> <option th:each="item : ${@demoCodeMap.getDayItems()}" th:value="${item.key}" th:text="${item.value}" /> </select>日 <span th:if="*{#fields.hasErrors('birthDayRequired')}" th:errors="*{birthDayRequired}" class="errorMessage"></span> <span th:if="*{#fields.hasErrors('birthYear')}" th:errors="*{birthYear}" class="errorMessage"></span> </td> </tr> <tr> <td align="left" valign="top">性別:</td> <td> <for th:each="item : ${@demoCodeMap.getSexItems()}"> <input type="radio" name="sex" th:value="${item.key}" th:text="${item.value}" th:field="*{sex}" th:errorclass="fieldError" /> </for> <span th:if="*{#fields.hasErrors('sex')}" th:errors="*{sex}" class="errorMessage"></span> <span th:if="*{#fields.hasErrors('sexInvalid')}" th:errors="*{sexInvalid}" class="errorMessage"></span> </td> </tr> <tr> <td align="left" valign="top">メモ:</td> <td> <textarea rows="6" cols="40" th:value="*{memo}" th:field="*{memo}"></textarea> </td> </tr> <tr> <td align="left" valign="top">入力確認:</td> <td> <input type="checkbox" name="checked" th:value="確認済" th:field="*{checked}" th:errorclass="fieldError" /> <span th:if="*{#fields.hasErrors('checked')}" th:errors="*{checked}" class="errorMessage"></span> </td> </tr> </table> <br/><br/> <input type="submit" name="next" value="確認" /> <input type="submit" name="back" value="戻る" /> </form> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | <!DOCTYPE html> <html lang="jp" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>確認画面</title> </head> <body> <p>入力内容を確認し、問題なければ「送信」ボタンを押下してください。</p> <form method="post" th:action="@{/send}" th:object="${demoForm}"> <table border="0"> <tr> <td align="left" valign="top">名前: </td> <td> <span th:text="*{name}"> ここに名前が表示されます </span> </td> </tr> <tr> <td align="left" valign="top">生年月日: </td> <td> <span th:text="*{birthYear} + '年' + ${@demoCodeMap.getMonthItems().get('__*{birthMonth}__')} + '月' + ${@demoCodeMap.getDayItems().get('__*{birthDay}__')} + '日'"> ここに生年月日が表示されます </span> </td> </tr> <tr> <td align="left" valign="top">性別: </td> <td> <span th:text="${@demoCodeMap.getSexItems().get('__*{sex}__')}"> ここに性別が表示されます </span> </td> </tr> <tr> <td align="left" valign="top">メモ: </td> <td> <th:block th:if="*{memo}"> <th:block th:each="memoStr, memoStat :" + " *{memo.split('\r\n|\r|\n', -1)}"> <th:block th:text="${memoStr}"/> <br th:if="${!memoStat.last}"/> </th:block> </th:block> </td> </tr> <tr> <td align="left" valign="top">確認チェック: </td> <td> <span th:text="*{checked}"> ここに確認チェック内容が表示されます </span> </td> </tr> </table> <br/><br/> <input type="submit" name="next" value="送信" /> <input type="submit" name="back" value="戻る" /> </form> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <!DOCTYPE html> <html lang="jp" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>削除確認画面</title> </head> <body> <p>下記内容を削除してよろしいでしょうか?問題なければ「送信」ボタンを押下してください。</p> <form method="post" th:action="@{/delete}" th:object="${demoForm}"> <table border="0"> <tr> <td align="left" valign="top">名前: </td> <td> <span th:text="*{name}"> ここに名前が表示されます </span> </td> </tr> <tr> <td align="left" valign="top">生年月日: </td> <td> <span th:text="*{birthYear} + '年' + ${@demoCodeMap.getMonthItems().get('__*{birthMonth}__')} + '月' + ${@demoCodeMap.getDayItems().get('__*{birthDay}__')} + '日'"> ここに生年月日が表示されます </span> </td> </tr> <tr> <td align="left" valign="top">性別: </td> <td> <span th:text="${@demoCodeMap.getSexItems().get('__*{sex}__')}"> ここに性別が表示されます </span> </td> </tr> <tr> <td align="left" valign="top">メモ: </td> <td> <th:block th:if="*{memo}"> <th:block th:each="memoStr, memoStat : " + "*{memo.split('\r\n|\r|\n', -1)}"> <th:block th:text="${memoStr}"/> <br th:if="${!memoStat.last}"/> </th:block> </th:block> </td> </tr> </table> <br/><br/> <input type="submit" name="next" value="送信" /> <input type="submit" name="back" value="戻る" /> </form> </body> </html> |
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-web-codelist-thymeleaf/demo
サンプルプログラムの実行結果
サンプルプログラムを実行すると、以下の記事に記載されているデータ更新・チェック処理・ページング処理が実行される。
実際、以下の画面のように、コードリストの値が設定されていることが確認できる。
要点まとめ
- コードリストの値は、Springのコンテキスト管理下にあれば、Thymeleafで直接参照することができる。