Spring Boot 基本

Formクラスに記載していたコードリストの値をThymeleafで直接参照してみた

これまでこのブログで記載してきたSpring Bootアプリケーションのソースコードは、コードリストの値をFormクラスに記載していたが、FormクラスやControllerクラスを経由しなくても、Springのコンテキスト管理下にあるコードリストの値をThymeleafで直接参照することができる。

今回は、Formクラスに記載していたコードリストの値をThymeleafで直接参照するようにしてみたので、そのサンプルプログラムを共有する。

前提条件

下記記事の実装が完了していること。

Spring Bootで全角チェック処理を行う独自アノテーションを作成してみたSpring Bootの独自アノテーションで、特定のフィールドに対するチェック処理も実装することができる。今回は、特定のフィールドの全角...

サンプルプログラムの構成

作成したサンプルプログラムの構成は以下の通り。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから今回追加・変更したプログラムである。

DemoCodeMapクラスの内容は以下の通りで、DemoFormクラス・SearchFormクラスに記載していたコードリストの内容を、Springのコンテキスト管理下に記載している。

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クラスに記載したコードリストを削除している。

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);
    }

}
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()}」と修正している。

<!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>
「Envader」はLinuxコマンドやDatabase SQL等のスキルを、環境構築不要で習得できる学習サイトだった「Envader」は、ITエンジニアとしてよく使うLinuxコマンドやDatabase SQL等のスキルを、解説を読んだ上で、問題を解き...

入力画面(input.html)・確認画面(confirm.html)・削除確認画面(confirm_delete.html)の内容は以下の通りで、検索画面と同じ修正を行っている。

<!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>
<!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>
<!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 BootのWEB画面上でCRUDを含むOracleアクセス処理を実装してみた(完成イメージ編)今回は、C(Create)・R(Read)・U(Update)・D(Delete)を一通り含むOracle接続処理をSpring Boo...
Spring Bootのチェック処理を独自アノテーションで実行してみたSpring Bootでのチェック処理は、よく使うものについては独自アノテーションで作成しておくことができる。今回は、独自アノテーション...
Spring BootのWEBの一覧画面上でページング処理を実装してみた(完成イメージと前提条件)今回は、Spring Bootの一覧画面上でページング処理を実装してみたので、そのサンプルプログラムを共有する。 ページング処理で...

実際、以下の画面のように、コードリストの値が設定されていることが確認できる。
サンプルプログラムの実行結果_1

サンプルプログラムの実行結果_2 サンプルプログラムの実行結果_3

要点まとめ

  • コードリストの値は、Springのコンテキスト管理下にあれば、Thymeleafで直接参照することができる。