Spring Boot DB連携

MongoTemplateを利用して複雑な条件検索を行ってみた

今回は、「MongoTemplate」を使って、柔軟な条件指定によるMongoDBのデータ参照を行ってみたので、そのサンプルプログラムを共有する。

前提条件

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

Spring Boot上でMongoDBをMongoTemplateで操作してみた「MongoTemplate」を利用すると、「MongoRepository」より柔軟な条件指定によるデータ参照/作成/更新/削除を簡単...

完成した画面イメージ

下記サイトの画面の「サンプルプログラムの実行結果」を参照のこと。

SQLログ出力内容をカスタマイズしてみた今回は、SQLログ出力内容をカスタマイズし、SQLの実行時間や呼出メソッドをSQLログに出力してみたので、そのサンプルプログラムを共有す...

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

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

サービスクラスの内容は以下の通り。

package com.example.demo;

import org.springframework.data.domain.Pageable;
import java.util.List;

public interface DemoService {

    /**
     * ユーザーデータリストを取得
     * @param searchForm 検索用Formオブジェクト
     * @param pageable ページネーションオブジェクト
     * @return ユーザーデータリスト
     */
    List<DemoForm> demoFormList(SearchForm searchForm, Pageable pageable);

    /**
     * 引数のIDに対応するユーザーデータを取得
     * @param pKeyID MongoDBの主キー
     * @return ユーザーデータ
     */
    DemoForm findByPKeyId(String pKeyID);

    /**
     * 引数のユーザーデータを削除
     * @param demoForm 追加・更新用Formオブジェクト
     */
    void delete(DemoForm demoForm);

    /**
     * 引数のユーザーデータがあれば更新し、無ければ追加
     * @param demoForm 追加・更新用Formオブジェクト
     */
    void createOrUpdate(DemoForm demoForm);

    /**
     * ユーザー検索時に利用するページング用オブジェクトを生成する
     * @param pageNumber ページ番号
     * @return ページング用オブジェクト
     */
    Pageable getPageable(int pageNumber);

    /**
     * 一覧画面の全ページ数を取得する
     * @param searchForm 検索用Formオブジェクト
     * @return 全ページ数
     */
    int getAllPageNum(SearchForm searchForm);
}



また、サービスクラスの実装クラスの内容は以下の通りで、getUserDataListメソッド内で、MongoTemplateを利用した条件検索を実施している。

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.ASC;
import static org.springframework.data.domain.Sort.Direction.DESC;

@Service
public class DemoServiceImpl implements DemoService{

    /**
     * ユーザーデータ(user_data)へアクセスするMongoTemplate
     */
    @Autowired
    private MongoTemplate template;

    /**
     * 1ページに表示する行数(application.propertiesから取得)
     */
    @Value("${demo.list.pageSize}")
    private String listPageSize;

    /**
     * {@inheritDoc}
     */
    @Override
    public List<DemoForm> demoFormList(SearchForm searchForm, Pageable pageable) {
        List<DemoForm> demoFormList = new ArrayList<>();
        //ユーザーデータテーブル(user_data)から取得する開始位置・終了位置を算出
        int limit = Integer.parseInt(listPageSize);
        int offset = (searchForm.getCurrentPageNum() - 1) * limit;
        //ユーザーデータテーブル(user_data)から検索条件に合うデータを取得する
        List<UserData> userDataList = getUserDataList(searchForm, offset, limit);
        for (UserData userData : userDataList) {
            demoFormList.add(getDemoForm(userData));
        }
        return demoFormList;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public DemoForm findByPKeyId(String pKeyID) {
        UserData userData = template.findById(pKeyID, UserData.class);
        return getDemoForm(userData);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(readOnly = false)
    public void delete(DemoForm demoForm){
        UserData userData = getUserData(demoForm);
        template.remove(userData);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(readOnly = false)
    public void createOrUpdate(DemoForm demoForm){
        //更新・追加処理を行うエンティティを生成
        UserData userData = getUserData(demoForm);
        //追加・更新処理
        if(demoForm.getId() == null){
            Query query = new Query();
            query.with(new Sort(DESC, "id"));
            UserData tmpUserData = template.findOne(query, UserData.class);
            userData.setId(tmpUserData == null ? 1 : tmpUserData.getId() + 1);
            template.save(userData);
        }else{
            template.save(userData);
        }
    }

    /**
     * DemoFormオブジェクトに引数のユーザーデータの各値を設定する
     * @param userData ユーザーデータ
     * @return DemoFormオブジェクト
     */
    private DemoForm getDemoForm(UserData userData){
        if(userData == null){
            return null;
        }
        DemoForm demoForm = new DemoForm();
        demoForm.setPKeyId(userData.getPKeyId());
        demoForm.setId(String.valueOf(userData.getId()));
        demoForm.setName(userData.getName());
        demoForm.setBirthYear(String.valueOf(userData.getBirth_year()));
        demoForm.setBirthMonth(String.valueOf(userData.getBirth_month()));
        demoForm.setBirthDay(String.valueOf(userData.getBirth_day()));
        demoForm.setSex(String.valueOf(userData.getSex()));
        demoForm.setMemo(userData.getMemo());
        demoForm.setSex_value(userData.getSex() == 1 ? "男" : "女");
        return demoForm;
    }

    /**
     * UserDataオブジェクトに引数のフォームの各値を設定する
     * @param demoForm DemoFormオブジェクト
     * @return ユーザーデータ
     */
    private UserData getUserData(DemoForm demoForm){
        UserData userData = new UserData();
        userData.setPKeyId(demoForm.getPKeyId());
        if(!StringUtils.isEmpty(demoForm.getId())){
            userData.setId(Long.valueOf(demoForm.getId()));
        }
        userData.setName(demoForm.getName());
        userData.setBirth_year(Integer.valueOf(demoForm.getBirthYear()));
        userData.setBirth_month(Integer.valueOf(demoForm.getBirthMonth()));
        userData.setBirth_day(Integer.valueOf(demoForm.getBirthDay()));
        userData.setSex(Integer.valueOf(demoForm.getSex()));
        userData.setMemo(demoForm.getMemo());
        return userData;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Pageable getPageable(int pageNumber){
        Pageable pageable = new Pageable() {
            @Override
            public int getPageNumber() {
                //現在ページ数を返却
                return pageNumber;
            }

            @Override
            public int getPageSize() {
                //1ページに表示する行数を返却
                //listPageSizeは、本プログラムの先頭に定義している
                return Integer.parseInt(listPageSize);
            }

            @Override
            public long getOffset() {
                //表示開始位置を返却
                //例えば、1ページに2行表示する場合の、2ページ目の表示開始位置は
                //(2-1)*2+1=3 で計算される
                return ((pageNumber - 1) * Integer.parseInt(listPageSize) + 1);
            }

            @Override
            public Sort getSort() {
                //ソートは使わないのでnullを返却
                return null;
            }

            @Override
            public Pageable next() {
                return null;
            }

            @Override
            public Pageable previousOrFirst() {
                return null;
            }

            @Override
            public Pageable first() {
                return null;
            }

            @Override
            public boolean hasPrevious() {
                return false;
            }
        };
        return pageable;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getAllPageNum(SearchForm searchForm) {
        //1ページに表示する行数を取得
        int listPageSizeNum = Integer.parseInt(listPageSize);
        if(listPageSizeNum == 0){
            return 1;
        }
        //一覧画面に表示する全データを取得
        List<UserData> userDataList = getUserDataList(searchForm, 0, 0);
        //全ページ数を計算
        //例えば、1ページに2行表示する場合で、全データ件数が5の場合、
        //(5+2-1)/2=3 と計算される
        int allPageNum = (userDataList.size() + listPageSizeNum - 1) / listPageSizeNum;
        return allPageNum == 0 ? 1 : allPageNum;
    }

    /**
     * 検索用Formオブジェクトの条件にあてはまるユーザーデータを取得する
     * @param searchForm 検索用Formオブジェクト
     * @param offset  取得開始位置
     * @param limit   取得件数(全件取得する場合は0を指定)
     * @return ユーザーデータリスト
     */
    private List<UserData> getUserDataList(SearchForm searchForm
            , int offset, int limit){
        Query query = new Query();
        Criteria criteria1 = null;
        Criteria criteria2 = null;
        //検索条件を指定
        //氏名が指定された場合
        if(!StringUtils.isEmpty(searchForm.getSearchName())){
            query.addCriteria(Criteria.where("name")
                 .regex(".*" + searchForm.getSearchName() + ".*", "i"));
        }
        //生年月日(From)が指定された場合の条件を作成
        if(!StringUtils.isEmpty(searchForm.getFromBirthYear())){
            criteria1 = new Criteria().orOperator(
                    Criteria.where("birth_year")
                       .gt(Integer.parseInt(searchForm.getFromBirthYear())),
                    new Criteria().andOperator(
                            Criteria.where("birth_year")
                               .is(Integer.parseInt(searchForm.getFromBirthYear())),
                            Criteria.where("birth_month")
                               .gt(Integer.parseInt(searchForm.getFromBirthMonth()))
                    ),
                    new Criteria().andOperator(
                            Criteria.where("birth_year")
                               .is(Integer.parseInt(searchForm.getFromBirthYear())),
                            Criteria.where("birth_month")
                               .is(Integer.parseInt(searchForm.getFromBirthMonth())),
                            Criteria.where("birth_day")
                               .gte(Integer.parseInt(searchForm.getFromBirthDay()))
                    )
            );
        }
        //生年月日(To)が指定された場合の条件を作成
        if(!StringUtils.isEmpty(searchForm.getToBirthYear())){
            criteria2 = new Criteria().orOperator(
                    Criteria.where("birth_year")
                            .lt(Integer.parseInt(searchForm.getToBirthYear())),
                    new Criteria().andOperator(
                            Criteria.where("birth_year")
                                .is(Integer.parseInt(searchForm.getToBirthYear())),
                            Criteria.where("birth_month")
                                .lt(Integer.parseInt(searchForm.getToBirthMonth()))
                    ),
                    new Criteria().andOperator(
                            Criteria.where("birth_year")
                                .is(Integer.parseInt(searchForm.getToBirthYear())),
                            Criteria.where("birth_month")
                                .is(Integer.parseInt(searchForm.getToBirthMonth())),
                            Criteria.where("birth_day")
                                .lte(Integer.parseInt(searchForm.getToBirthDay()))
                    )
            );
        }
        //生年月日(From), 生年月日(To)の両方が指定された場合
        if(criteria1 != null && criteria2 != null){
            query.addCriteria(new Criteria().andOperator(criteria1, criteria2));
        //生年月日(From)が指定された場合
        }else if(criteria1 != null){
            query.addCriteria(criteria1);
        //生年月日(To)が指定された場合
        }else if(criteria2 != null){
            query.addCriteria(criteria2);
        }
        //性別が指定された場合
        if(!StringUtils.isEmpty(searchForm.getSearchSex())){
            query.addCriteria(Criteria.where("sex")
                 .is(Integer.parseInt(searchForm.getSearchSex())));
        }
        //ソート順を指定
        query.with(new Sort(ASC, "id"));
        //開始位置(offset)・終了位置(limit)を指定
        query.skip(offset);
        if(limit != 0){
            query.limit(limit);
        }
        List<UserData> userDataList = template.find(query, UserData.class);
        return userDataList;
    }

}



また、コントローラクラスの内容は以下の通り。

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.data.domain.Pageable;
import java.util.ArrayList;
import java.util.List;

@Controller
@SessionAttributes(types = {DemoForm.class, SearchForm.class})
public class DemoController {

    /**
     * Demoサービスクラスへのアクセス
     */
    @Autowired
    private DemoService demoService;

    /**
     * ユーザーデータテーブル(user_data)のデータを取得して返却する
     * @return ユーザーデータリスト
     */
    @ModelAttribute("demoFormList")
    public List<DemoForm> userDataList(){
        List<DemoForm> demoFormList = new ArrayList<>();
        return demoFormList;
    }

    /**
     * 追加・更新用Formオブジェクトを初期化して返却する
     * @return 追加・更新用Formオブジェクト
     */
    @ModelAttribute("demoForm")
    public DemoForm createDemoForm(){
        DemoForm demoForm = new DemoForm();
        return demoForm;
    }

    /**
     * 検索用Formオブジェクトを初期化して返却する
     * @return 検索用Formオブジェクト
     */
    @ModelAttribute("searchForm")
    public SearchForm createSearchForm(){
        SearchForm searchForm = new SearchForm();
        return searchForm;
    }

    /**
     * 初期表示(検索)画面に遷移する
     * @return 検索画面へのパス
     */
    @RequestMapping("/")
    public String index(){
        return "search";
    }

    /**
     * 検索処理を行い、一覧画面に遷移する
     * @param searchForm 検索用Formオブジェクト
     * @param result バインド結果
     * @param model Modelオブジェクト
     * @return 一覧画面へのパス
     */
    @PostMapping("/search")
    public String search(@Validated SearchForm searchForm
            , BindingResult result, Model model){
        //検索用Formオブジェクトのチェック処理でエラーがある場合は、
        //検索画面のままとする
        if(result.hasErrors()){
            return "search";
        }
        //現在ページ数を1ページ目に設定し、一覧画面に遷移する
        searchForm.setCurrentPageNum(1);
        return movePageInList(model, searchForm);
    }

    /**
     * 一覧画面で「先頭へ」リンク押下時に次ページを表示する
     * @param searchForm 検索用Formオブジェクト
     * @param model Modelオブジェクト
     * @return 一覧画面へのパス
     */
    @GetMapping("/firstPage")
    public String firstPage(SearchForm searchForm, Model model){
        //現在ページ数を先頭ページに設定する
        searchForm.setCurrentPageNum(1);
        return movePageInList(model, searchForm);
    }

    /**
     * 一覧画面で「前へ」リンク押下時に次ページを表示する
     * @param searchForm 検索用Formオブジェクト
     * @param model Modelオブジェクト
     * @return 一覧画面へのパス
     */
    @GetMapping("/backPage")
    public String backPage(SearchForm searchForm, Model model){
        //現在ページ数を前ページに設定する
        searchForm.setCurrentPageNum(searchForm.getCurrentPageNum() - 1);
        return movePageInList(model, searchForm);
    }

    /**
     * 一覧画面で「次へ」リンク押下時に次ページを表示する
     * @param searchForm 検索用Formオブジェクト
     * @param model Modelオブジェクト
     * @return 一覧画面へのパス
     */
    @GetMapping("/nextPage")
    public String nextPage(SearchForm searchForm, Model model){
        //現在ページ数を次ページに設定する
        searchForm.setCurrentPageNum(searchForm.getCurrentPageNum() + 1);
        return movePageInList(model, searchForm);
    }

    /**
     * 一覧画面で「最後へ」リンク押下時に次ページを表示する
     * @param searchForm 検索用Formオブジェクト
     * @param model Modelオブジェクト
     * @return 一覧画面へのパス
     */
    @GetMapping("/lastPage")
    public String lastPage(SearchForm searchForm, Model model){
        //現在ページ数を最終ページに設定する
        searchForm.setCurrentPageNum(demoService.getAllPageNum(searchForm));
        return movePageInList(model, searchForm);
    }

    /**
     * 更新処理を行う画面に遷移する
     * @param id 更新対象のID
     * @param model Modelオブジェクト
     * @return 入力・更新画面へのパス
     */
    @GetMapping("/update")
    public String update(@RequestParam("id") String id, Model model){
        //更新対象のユーザーデータを取得
        DemoForm demoForm = demoService.findByPKeyId(id);
        //ユーザーデータを更新
        model.addAttribute("demoForm", demoForm);
        return "input";
    }

    /**
     * 削除確認画面に遷移する
     * @param id 更新対象のID
     * @param model Modelオブジェクト
     * @return 削除確認画面へのパス
     */
    @GetMapping("/delete_confirm")
    public String delete_confirm(@RequestParam("id") String id, Model model){
        //削除対象のユーザーデータを取得
        DemoForm demoForm = demoService.findByPKeyId(id);
        //ユーザーデータを更新
        model.addAttribute("demoForm", demoForm);
        return "confirm_delete";
    }

    /**
     * 削除処理を行う
     * @param demoForm 追加・更新用Formオブジェクト
     * @return 一覧画面の表示処理
     */
    @PostMapping(value = "/delete", params = "next")
    public String delete(DemoForm demoForm){
        //指定したユーザーデータを削除
        demoService.delete(demoForm);
        //一覧画面に遷移
        return "redirect:/to_index";
    }

    /**
     * 削除完了後に一覧画面に戻る
     * @param searchForm 検索用Formオブジェクト
     * @param model Modelオブジェクト
     * @return 一覧画面
     */
    @GetMapping("/to_index")
    public String toIndex(SearchForm searchForm, Model model){
        //一覧画面に戻り、1ページ目のリストを表示する
        searchForm.setCurrentPageNum(1);
        return movePageInList(model, searchForm);
    }

    /**
     * 削除確認画面から一覧画面に戻る
     * @param model Modelオブジェクト
     * @param searchForm 検索用Formオブジェクト
     * @return 一覧画面
     */
    @PostMapping(value = "/delete", params = "back")
    public String confirmDeleteBack(Model model, SearchForm searchForm){
        //一覧画面に戻る
        return movePageInList(model, searchForm);
    }

    /**
     * 追加処理を行う画面に遷移する
     * @param model Modelオブジェクト
     * @return 入力・更新画面へのパス
     */
    @PostMapping(value = "/add", params = "next")
    public String add(Model model){
        model.addAttribute("demoForm", new DemoForm());
        return "input";
    }

    /**
     * 追加処理を行う画面から検索画面に戻る
     * @return 検索画面へのパス
     */
    @PostMapping(value = "/add", params = "back")
    public String addBack(){
        return "search";
    }

    /**
     * エラーチェックを行い、エラーが無ければ確認画面に遷移し、
     * エラーがあれば入力画面のままとする
     * @param demoForm 追加・更新用Formオブジェクト
     * @param result バインド結果
     * @return 確認画面または入力画面へのパス
     */
    @PostMapping(value = "/confirm", params = "next")
    public String confirm(@Validated DemoForm demoForm, BindingResult result){
        //追加・更新用Formオブジェクトのチェック処理でエラーがある場合は、
        //入力画面のままとする
        if(result.hasErrors()){
            return "input";
        }
        //エラーが無ければ確認画面に遷移する
        return "confirm";
    }

    /**
     * 一覧画面に戻る
     * @param model Modelオブジェクト
     * @param searchForm 検索用Formオブジェクト
     * @return 一覧画面の表示処理
     */
    @PostMapping(value = "/confirm", params = "back")
    public String confirmBack(Model model, SearchForm searchForm){
        //一覧画面に戻る
        return movePageInList(model, searchForm);
    }

    /**
     * 完了画面に遷移する
     * @param demoForm 追加・更新用Formオブジェクト
     * @param result バインド結果
     * @return 完了画面
     */
    @PostMapping(value = "/send", params = "next")
    public String send(@Validated DemoForm demoForm, BindingResult result){
        //チェック処理を行い、エラーがなければ、更新・追加処理を行う
        if(result.hasErrors()){
            return "input";
        }
        demoService.createOrUpdate(demoForm);
        return "redirect:/complete";
    }

    /**
     * 完了画面に遷移する
     * @param sessionStatus セッションステータス
     * @return 完了画面
     */
    @GetMapping("/complete")
    public String complete(SessionStatus sessionStatus){
        //セッションオブジェクトを破棄
        sessionStatus.setComplete();
        return "complete";
    }

    /**
     * 入力画面に戻る
     * @return 入力画面
     */
    @PostMapping(value = "/send", params = "back")
    public String sendBack(){
        return "input";
    }

    /**
     * 一覧画面に戻り、指定した現在ページのリストを表示する
     * @param model Modelオブジェクト
     * @param searchForm 検索用Formオブジェクト
     * @return 一覧画面の表示処理
     */
    private String movePageInList(Model model, SearchForm searchForm){
        //現在ページ数, 総ページ数を設定
        model.addAttribute("currentPageNum", searchForm.getCurrentPageNum());
        model.addAttribute("allPageNum", demoService.getAllPageNum(searchForm));
        //ページング用オブジェクトを生成し、現在ページのユーザーデータリストを取得
        Pageable pageable = demoService.getPageable(searchForm.getCurrentPageNum());
        List<DemoForm> demoFormList = demoService.demoFormList(searchForm, pageable);
        //ユーザーデータリストを更新
        model.addAttribute("demoFormList", demoFormList);
        return "list";
    }
}



さらに、定義ファイルの内容は以下の通りで、MongoDBの接続情報に加え、一覧画面で1ページに表示する行数を記載している。

server:
  port: 8084
# MongoDB接続情報
spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: test
# 一覧画面で1ページに表示する行数
demo:
  list:
    pageSize: 2



また、赤枠のHTMLファイルと、メッセージプロパティの内容は以下の通り。

<!DOCTYPE html>
<html lang="ja" 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 : *{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 : *{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 : *{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 : *{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 : *{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>
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>index page</title>
</head>
<body>
    ユーザーデータテーブル(user_data)の全データ<br/><br/>

    <table border="1" cellpadding="5">
        <tr>
            <th>ID</th>
            <th>名前</th>
            <th>生年月日</th>
            <th>性別</th>
            <th></th>
            <th></th>
        </tr>
        <tr th:each="obj : ${demoFormList}">
            <td th:text="${obj.id}"></td>
            <td th:text="${obj.name}"></td>
            <td th:text="|${obj.birthYear}年 ${obj.birthMonth}月 ${obj.birthDay}日|"></td>
            <td th:text="${obj.sex_value}"></td>
            <td><a href="/update" th:href="@{/update(id=${'__${obj.pKeyId}__'})}">更新</a></td>
            <td><a href="/delete_confirm" th:href="@{/delete_confirm(id=${'__${obj.pKeyId}__'})}">削除</a></td>
        </tr>
    </table>
    <br/><br/>
    <table border="0">
        <tr>
            <td width="70">
                <span th:if="${currentPageNum} != 1">
                    <a href="/firstPage" th:href="@{/firstPage}">先頭へ</a>
                </span>
            </td>
            <td width="50">
                <span th:if="${currentPageNum} != 1">
                    <a href="/backPage" th:href="@{/backPage}">前へ</a>
                </span>
            </td>
            <td width="50">
                <span th:text="${currentPageNum}"></span>&nbsp;/&nbsp;<span th:text="${allPageNum}"></span>
            </td>
            <td width="50">
                <span th:if="${currentPageNum} != ${allPageNum}">
                    <a href="/nextPage" th:href="@{/nextPage}">次へ</a>
                </span>
            </td>
            <td width="70">
                <span th:if="${currentPageNum} != ${allPageNum}">
                    <a href="/lastPage" th:href="@{/lastPage}">最後へ</a>
                </span>
            </td>
        </tr>
    </table>
    <br/><br/>
    <form method="post" th:action="@{/add}">
        <input type="submit" name="next" value="データ追加" /><br/><br/>
        <input type="submit" name="back" value="戻る" />
    </form>
</body>
</html>
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>完了画面</title>
</head>
<body>
   お申し込みが完了しました。<br/><br/>

    <form method="post" th:action="@{/}">
        <input type="submit" value="検索画面に戻る" />
    </form>
</body>
</html>



#メッセージ
validation.date-empty={0}を入力してください。
validation.date-invalidate=生年月日が存在しない日付になっています。
validation.date-future=生年月日が未来の日付になっています。
validation.empty-msg=
javax.validation.constraints.NotEmpty.message={0}を入力してください。
validation.sex-invalidate=性別に不正な値が入っています。
validation.date-invalidate-from=生年月日(From)の日付が不正です。
validation.date-invalidate-to=生年月日(To)の日付が不正です。
validation.date-invalidate-from-to=生年月日(From)が生年月日(To)より大きくなっています。
validation.zenkaku={0}は全角で入力してください。

#フィールド名
name=名前
sex=性別
checked=確認チェック
birthDayRequired=生年月日

その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-mongo-template-2/demo

要点まとめ

  • 「MongoTemplate」を使って、柔軟な条件指定によるMongoDBのデータ参照を行うには、Criteriaクラスを利用して検索条件の指定を行う。