今回も引き続き、Spring BootのWEB画面上でデータ検索機能を追加した実装について述べる。ここでは、具体的なサンプルプログラムのソースコードを共有する。
前提条件
下記記事を参照のこと。
作成したサンプルプログラムの内容
作成したサンプルプログラムの構成は以下の通り。
なお、上図の赤枠は、前提条件に記載したソースコードと比較し、変更になったソースコードを示す。赤枠のソースコードについては今後記載する。
まず、検索用のFormオブジェクトは下記の通り。名前・生年月日(From,To)・性別の項目とプルダウンを設定している。
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 | package com.example.demo; import lombok.Data; import java.util.LinkedHashMap; import java.util.Map; /** * Formオブジェクトのクラス */ @Data 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; /** 生年月日_月の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; } } |
次に、データベースにアクセスするMapperクラスは以下の通り。全件検索するfindAllメソッドを、検索条件指定により検索するfindBySearchFormメソッドに変更している。
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 org.apache.ibatis.annotations.Mapper; import java.util.Collection; @Mapper public interface UserDataMapper { /** * ユーザーデータテーブル(user_data)から検索条件に合うデータを取得する * @param searchForm 検索用Formオブジェクト * @return ユーザーデータテーブル(user_data)の検索条件に合うデータ */ Collection<UserData> findBySearchForm(SearchForm searchForm); /** * 指定したIDをもつユーザーデータテーブル(user_data)のデータを取得する * @param id ID * @return ユーザーデータテーブル(user_data)の指定したIDのデータ */ UserData findById(Long id); /** * 指定したIDをもつユーザーデータテーブル(user_data)のデータを削除する * @param id ID */ void deleteById(Long id); /** * 指定したユーザーデータテーブル(user_data)のデータを追加する * @param userData ユーザーデータテーブル(user_data)の追加データ */ void create(UserData userData); /** * 指定したユーザーデータテーブル(user_data)のデータを更新する * @param userData ユーザーデータテーブル(user_data)の更新データ */ void update(UserData userData); /** * ユーザーデータテーブル(user_data)の最大値IDを取得する * @return ユーザーデータテーブル(user_data)の最大値ID */ long findMaxId(); } |
また、Mapperクラスに対応するXMLファイルは以下の通り。findBySearchFormメソッド内のifタグにより、条件分岐を利用した動的SQL文を生成している。
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 | <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.UserDataMapper"> <select id="findBySearchForm" parameterType="com.example.demo.SearchForm" resultType="com.example.demo.UserData"> SELECT u.id, u.name, u.birth_year as birthY, u.birth_month as birthM , u.birth_day as birthD, u.sex as sex, m.sex_value as sex_value FROM USER_DATA u, M_SEX m WHERE u.sex = m.sex_cd <if test="searchName != null and searchName != ''"> AND u.name like '%' || #{searchName} || '%' </if> <if test="fromBirthYear != null and fromBirthYear != ''"> AND #{fromBirthYear} || lpad(#{fromBirthMonth}, 2, '0') || lpad(#{fromBirthDay}, 2, '0') <= u.birth_year || lpad(u.birth_month, 2, '0') || lpad(u.birth_day, 2, '0') </if> <if test="toBirthYear != null and toBirthYear != ''"> AND u.birth_year || lpad(u.birth_month, 2, '0') || lpad(u.birth_day, 2, '0') <= #{toBirthYear} || lpad(#{toBirthMonth}, 2, '0') || lpad(#{toBirthDay}, 2, '0') </if> <if test="searchSex != null and searchSex != ''"> AND u.sex = #{searchSex} </if> ORDER BY u.id </select> <select id="findById" resultType="com.example.demo.UserData"> SELECT id, name, birth_year as birthY , birth_month as birthM , birth_day as birthD, sex FROM USER_DATA WHERE id = #{id} </select> <delete id="deleteById" parameterType="java.lang.Long"> DELETE FROM USER_DATA WHERE id = #{id} </delete> <insert id="create" parameterType="com.example.demo.UserData"> INSERT INTO USER_DATA ( id, name, birth_year, birth_month, birth_day, sex ) VALUES (#{id}, #{name}, #{birthY}, #{birthM}, #{birthD}, #{sex}) </insert> <update id="update" parameterType="com.example.demo.UserData"> UPDATE USER_DATA SET name = #{name}, birth_year = #{birthY} , birth_month = #{birthM}, birth_day = #{birthD}, sex = #{sex} WHERE id = #{id} </update> <select id="findMaxId" resultType="long"> SELECT NVL(max(id), 0) FROM USER_DATA </select> </mapper> |
さらに、検索画面「search.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 | <!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}"> <span th:if="*{#fields.hasErrors('fromBirthYear')}" th:errors="*{fromBirthYear}" class="errorMessage"></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"> <option value=""></option> <option th:each="item : *{getMonthItems()}" th:value="${item.key}" th:text="${item.value}"/> </select>月 <select th:field="*{fromBirthDay}" th:errorclass="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"> <option value=""></option> <option th:each="item : *{getMonthItems()}" th:value="${item.key}" th:text="${item.value}"/> </select>月 <select th:field="*{toBirthDay}" th:errorclass="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> |
その他、検索用Formのチェック処理を行うメソッド「checkSearchForm」をユーティリティクラスに追加している。
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | package com.example.demo; import java.time.LocalDate; import java.time.chrono.JapaneseChronology; import java.time.format.DateTimeFormatter; import java.time.format.ResolverStyle; import java.util.Locale; public class DateCheckUtil { /** 日付のフォーマット */ private final static String dateFormat = "uuuuMMdd"; /** * 日付チェック処理を行う * @param year 年 * @param month 月 * @param day 日 * @return 判定結果(1:年が空、2:月が空、3:日が空、4:年月日が不正、 * 5:年月日が未来日、0:正常) */ public static int checkDate(String year, String month, String day){ if(isEmpty(year)){ return 1; } if(isEmpty(month)){ return 2; } if(isEmpty(day)){ return 3; } String dateStr = year + addZero(month) + addZero(day); if(!isCorrectDate(dateStr, dateFormat)){ return 4; } if(isFutureDate(dateStr, dateFormat)){ return 5; } return 0; } /** * 検索用Formオブジェクトのチェック処理行う * @param searchForm 検索用Formオブジェクト * @return 判定結果(1:生年月日_fromが不正、2:生年月日_toが不正、 * 3:生年月日_from>生年月日_to、0:正常) */ public static int checkSearchForm(SearchForm searchForm){ //生年月日_fromが不正な場合 if(!checkSearchFormBirthday(searchForm.getFromBirthYear() , searchForm.getFromBirthMonth(), searchForm.getFromBirthDay())){ return 1; } //生年月日_toが不正な場合 if(!checkSearchFormBirthday(searchForm.getToBirthYear() , searchForm.getToBirthMonth(), searchForm.getToBirthDay())){ return 2; } //生年月日_from>生年月日_toの場合 if(!isEmpty(searchForm.getFromBirthYear()) && !isEmpty(searchForm.getToBirthYear())){ String fromBirthDay = searchForm.getFromBirthYear() + addZero(searchForm.getFromBirthMonth()) + addZero(searchForm.getFromBirthDay()); String toBirthDay = searchForm.getToBirthYear() + addZero(searchForm.getToBirthMonth()) + addZero(searchForm.getToBirthDay()); if(fromBirthDay.compareTo(toBirthDay) > 0){ return 3; } } //正常な場合 return 0; } /** * 検索用Form内の日付をチェックする * @param year 年 * @param month 月 * @param day 日 * @return 日付チェック結果 */ private static boolean checkSearchFormBirthday( String year, String month, String day){ //年・月・日が全て未指定の場合はチェックOKとする if(isEmpty(year) && isEmpty(month) && isEmpty(day)){ return true; } //年・月・日が全て指定されている場合は、日付が正しい場合にチェックOKとする if(!isEmpty(year) && !isEmpty(month) && !isEmpty(day)){ String dateStr = year + addZero(month) + addZero(day); if(isCorrectDate(dateStr, dateFormat)){ return true; } return false; } //年・月・日が指定あり/指定なしで混在している場合はチェックNGとする return false; } /** * DateTimeFormatterを利用して日付チェックを行う * @param dateStr チェック対象文字列 * @param dateFormat 日付フォーマット * @return 日付チェック結果 */ private static boolean isCorrectDate(String dateStr, String dateFormat){ if(isEmpty(dateStr) || isEmpty(dateFormat)){ return false; } //日付と時刻を厳密に解決するスタイルで、DateTimeFormatterオブジェクトを作成 DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat) .withResolverStyle(ResolverStyle.STRICT); try{ //チェック対象文字列をLocalDate型の日付に変換できれば、チェックOKとする LocalDate.parse(dateStr, df); return true; }catch(Exception e){ return false; } } /** * 日付の文字列が未来日かどうかを判定する * @param dateStr チェック対象文字列 * @param dateFormat 日付フォーマット * @return 判定結果 */ private static boolean isFutureDate(String dateStr, String dateFormat){ if(!isCorrectDate(dateStr, dateFormat)){ return false; } LocalDate dateStrDate = convertStrToLocalDate(dateStr, dateFormat); LocalDate now = LocalDate.now(); if(dateStrDate.isAfter(now)){ return true; } return false; } /** * 日付の文字列を日付型に変換した結果を返す * @param dateStr 日付の文字列 * @param dateFormat 日付のフォーマット * @return 変換後の文字列 */ private static LocalDate convertStrToLocalDate(String dateStr, String dateFormat){ if(isEmpty(dateStr) || isEmpty(dateFormat)){ return null; } //日付と時刻を厳密に解決するスタイルで、暦体系は和暦体系で、 //DateTimeFormatterオブジェクトを作成 DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat, Locale.JAPAN) .withChronology(JapaneseChronology.INSTANCE) .withResolverStyle(ResolverStyle.STRICT); //日付の文字列をLocalDate型に変換して返却 return LocalDate.parse(dateStr, df); } /** * 数値文字列が1桁の場合、頭に0を付けて返す * @param intNum 数値文字列 * @return 変換後数値文字列 */ private static String addZero(String intNum){ if(isEmpty(intNum)){ return intNum; } if(intNum.length() == 1){ return "0" + intNum; } return intNum; } /** * 引数の文字列がnull、空文字かどうかを判定する * @param str チェック対象文字列 * @return 文字列チェック結果 */ public static boolean isEmpty(String str){ if(str == null || "".equals(str)){ return true; } return false; } } |
さらに、コントローラクラスの内容は以下の通り。searchメソッドに、検索用Formのチェック処理・検索処理を追加している。
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | 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.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.SessionAttributes; 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 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 model Modelオブジェクト * @param result バインド結果 * @return 一覧画面へのパス */ @PostMapping("/search") public String search(SearchForm searchForm, Model model, BindingResult result){ //検索用Formオブジェクトのチェック処理 String returnVal = demoService.checkSearchForm(searchForm, result); if(returnVal != null){ return returnVal; } //ユーザーデータリストを取得 List<DemoForm> demoFormList = demoService.demoFormList(searchForm); //ユーザーデータリストを更新 model.addAttribute("demoFormList", demoFormList); return "list"; } /** * 更新処理を行う画面に遷移する * @param id 更新対象のID * @param model Modelオブジェクト * @return 入力・更新画面へのパス */ @GetMapping("/update") public String update(@RequestParam("id") String id, Model model){ //更新対象のユーザーデータを取得 DemoForm demoForm = demoService.findById(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.findById(id); //ユーザーデータを更新 model.addAttribute("demoForm", demoForm); return "confirm_delete"; } /** * 削除処理を行う * @param demoForm 追加・更新用Formオブジェクト * @return 一覧画面の表示処理 */ @PostMapping(value = "/delete", params = "next") public String delete(DemoForm demoForm){ //指定したユーザーデータを削除 demoService.deleteById(demoForm.getId()); //一覧画面に遷移 return "redirect:/to_index"; } /** * 削除完了後に一覧画面に戻る * @param searchForm 検索用Formオブジェクト * @param model Modelオブジェクト * @return 一覧画面 */ @GetMapping("/to_index") public String toIndex(SearchForm searchForm, Model model){ //一覧画面に遷移 //ユーザーデータリストを取得 List<DemoForm> demoFormList = demoService.demoFormList(searchForm); //ユーザーデータリストを更新 model.addAttribute("demoFormList", demoFormList); return "list"; } /** * 削除確認画面から一覧画面に戻る * @param model Modelオブジェクト * @param searchForm 検索用Formオブジェクト * @return 一覧画面 */ @PostMapping(value = "/delete", params = "back") public String confirmDeleteBack(Model model, SearchForm searchForm){ //一覧画面に遷移 //ユーザーデータリストを取得 List<DemoForm> demoFormList = demoService.demoFormList(searchForm); //ユーザーデータリストを更新 model.addAttribute("demoFormList", demoFormList); return "list"; } /** * 追加処理を行う画面に遷移する * @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){ //チェック処理を行い、画面遷移する return demoService.checkForm(demoForm, result, "confirm"); } /** * 一覧画面に戻る * @param model Modelオブジェクト * @param searchForm 検索用Formオブジェクト * @return 一覧画面の表示処理 */ @PostMapping(value = "/confirm", params = "back") public String confirmBack(Model model, SearchForm searchForm){ //ユーザーデータリストを取得 List<DemoForm> demoFormList = demoService.demoFormList(searchForm); //ユーザーデータリストを更新 model.addAttribute("demoFormList", demoFormList); return "list"; } /** * 完了画面に遷移する * @param demoForm 追加・更新用Formオブジェクト * @param result バインド結果 * @return 完了画面 */ @PostMapping(value = "/send", params = "next") public String send(@Validated DemoForm demoForm, BindingResult result){ //チェック処理を行い、エラーがなければ、更新・追加処理を行う String normalPath = "redirect:/complete"; String checkPath = demoService.checkForm(demoForm, result, "redirect:/complete"); if(normalPath.equals(checkPath)){ demoService.createOrUpdate(demoForm); } return checkPath; } /** * 完了画面に遷移する * @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"; } } |
https://www.purin-it.com/doctor-homenet
また、サービスクラスとその実装クラスは以下の通り。検索処理を呼び出すdemoFormListメソッドと、検索用Formのチェック処理を呼び出すcheckSearchFormメソッドを追加している。
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 | package com.example.demo; import org.springframework.validation.BindingResult; import java.util.List; public interface DemoService { /** * ユーザーデータリストを取得 * @param searchForm 検索用Formオブジェクト * @return ユーザーデータリスト */ List<DemoForm> demoFormList(SearchForm searchForm); /** * 引数のIDに対応するユーザーデータを取得 * @param id ID * @return ユーザーデータ */ DemoForm findById(String id); /** * 引数のIDに対応するユーザーデータを削除 * @param id ID */ void deleteById(String id); /** * 引数のユーザーデータがあれば更新し、無ければ削除 * @param demoForm 追加・更新用Formオブジェクト */ void createOrUpdate(DemoForm demoForm); /** * 追加・更新用Formオブジェクトのチェック処理を行い、画面遷移先を返す * @param demoForm 追加・更新用Formオブジェクト * @param result バインド結果 * @param normalPath 正常時の画面遷移先 * @return 画面遷移先 */ String checkForm(DemoForm demoForm, BindingResult result, String normalPath); /** * 検索用Formオブジェクトのチェック処理を行い、画面遷移先を返す * @param searchForm 検索用Formオブジェクト * @param result バインド結果 * @return 画面遷移先 */ String checkSearchForm(SearchForm searchForm, BindingResult result); } |
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BindingResult; import java.util.ArrayList; import java.util.Collection; import java.util.List; @Service public class DemoServiceImpl implements DemoService{ /** * ユーザーデータテーブル(user_data)へアクセスするマッパー */ @Autowired private UserDataMapper mapper; /** * {@inheritDoc} */ @Override public List<DemoForm> demoFormList(SearchForm searchForm) { List<DemoForm> demoFormList = new ArrayList<>(); //ユーザーデータテーブル(user_data)から検索条件に合うデータを取得する Collection<UserData> userDataList = mapper.findBySearchForm(searchForm); for (UserData userData : userDataList) { demoFormList.add(getDemoForm(userData)); } return demoFormList; } /** * {@inheritDoc} */ @Override public DemoForm findById(String id) { Long longId = stringToLong(id); UserData userData = mapper.findById(longId); return getDemoForm(userData); } /** * {@inheritDoc} */ @Override @Transactional(readOnly = false) public void deleteById(String id){ Long longId = stringToLong(id); mapper.deleteById(longId); } /** * {@inheritDoc} */ @Override @Transactional(readOnly = false) public void createOrUpdate(DemoForm demoForm){ //更新・追加処理を行うエンティティを生成 UserData userData = getUserData(demoForm); //追加・更新処理 if(demoForm.getId() == null){ userData.setId(mapper.findMaxId() + 1); mapper.create(userData); }else{ mapper.update(userData); } } /** * {@inheritDoc} */ @Override public String checkForm(DemoForm demoForm, BindingResult result, String normalPath){ //formオブジェクトのチェック処理を行う if(result.hasErrors()){ //エラーがある場合は、入力画面のままとする return "input"; } //生年月日の日付チェック処理を行う //エラーがある場合は、エラーメッセージ・エラーフィールドの設定を行い、 //入力画面のままとする int checkDate = DateCheckUtil.checkDate(demoForm.getBirthYear() , demoForm.getBirthMonth(), demoForm.getBirthDay()); switch(checkDate){ case 1: //生年月日_年が空文字の場合のエラー処理 result.rejectValue("birthYear", "validation.date-empty" , new String[]{"生年月日_年"}, ""); return "input"; case 2: //生年月日_月が空文字の場合のエラー処理 result.rejectValue("birthMonth", "validation.date-empty" , new String[]{"生年月日_月"}, ""); return "input"; case 3: //生年月日_日が空文字の場合のエラー処理 result.rejectValue("birthDay", "validation.date-empty" , new String[]{"生年月日_日"}, ""); return "input"; case 4: //生年月日の日付が不正な場合のエラー処理 result.rejectValue("birthYear", "validation.date-invalidate"); //生年月日_月・生年月日_日は、エラーフィールドの設定を行い、 //メッセージを空文字に設定している result.rejectValue("birthMonth", "validation.empty-msg"); result.rejectValue("birthDay", "validation.empty-msg"); return "input"; case 5: //生年月日の日付が未来日の場合のエラー処理 result.rejectValue("birthYear", "validation.date-future"); //生年月日_月・生年月日_日は、エラーフィールドの設定を行い、 //メッセージを空文字に設定している result.rejectValue("birthMonth", "validation.empty-msg"); result.rejectValue("birthDay", "validation.empty-msg"); return "input"; default: //性別が不正に書き換えられていないかチェックする if(!demoForm.getSexItems().keySet().contains(demoForm.getSex())){ result.rejectValue("sex", "validation.sex-invalidate"); return "input"; } //エラーチェックに問題が無いので、正常時の画面遷移先に遷移 return normalPath; } } /** * {@inheritDoc} */ @Override public String checkSearchForm(SearchForm searchForm, BindingResult result){ int checkDate =DateCheckUtil.checkSearchForm(searchForm); switch (checkDate){ case 1: //生年月日_fromが不正な場合のエラー処理 result.rejectValue("fromBirthYear", "validation.date-invalidate-from"); result.rejectValue("fromBirthMonth", "validation.empty-msg"); result.rejectValue("fromBirthDay", "validation.empty-msg"); return "search"; case 2: //生年月日_toが不正な場合のエラー処理 result.rejectValue("toBirthYear", "validation.date-invalidate-to"); result.rejectValue("toBirthMonth", "validation.empty-msg"); result.rejectValue("toBirthDay", "validation.empty-msg"); return "search"; case 3: //生年月日_from>生年月日_toの場合のエラー処理 result.rejectValue("fromBirthYear", "validation.date-invalidate-from-to"); result.rejectValue("fromBirthMonth", "validation.empty-msg"); result.rejectValue("fromBirthDay", "validation.empty-msg"); result.rejectValue("toBirthYear", "validation.empty-msg"); result.rejectValue("toBirthMonth", "validation.empty-msg"); result.rejectValue("toBirthDay", "validation.empty-msg"); return "search"; default: //正常な場合はnullを返却 return null; } } /** * DemoFormオブジェクトに引数のユーザーデータの各値を設定する * @param userData ユーザーデータ * @return DemoFormオブジェクト */ private DemoForm getDemoForm(UserData userData){ if(userData == null){ return null; } DemoForm demoForm = new DemoForm(); demoForm.setId(String.valueOf(userData.getId())); demoForm.setName(userData.getName()); demoForm.setBirthYear(String.valueOf(userData.getBirthY())); demoForm.setBirthMonth(String.valueOf(userData.getBirthM())); demoForm.setBirthDay(String.valueOf(userData.getBirthD())); demoForm.setSex(userData.getSex()); demoForm.setSex_value(userData.getSex_value()); return demoForm; } /** * UserDataオブジェクトに引数のフォームの各値を設定する * @param demoForm DemoFormオブジェクト * @return ユーザーデータ */ private UserData getUserData(DemoForm demoForm){ UserData userData = new UserData(); if(!DateCheckUtil.isEmpty(demoForm.getId())){ userData.setId(Long.valueOf(demoForm.getId())); } userData.setName(demoForm.getName()); userData.setBirthY(Integer.valueOf(demoForm.getBirthYear())); userData.setBirthM(Integer.valueOf(demoForm.getBirthMonth())); userData.setBirthD(Integer.valueOf(demoForm.getBirthDay())); userData.setSex(demoForm.getSex()); userData.setSex_value(demoForm.getSex_value()); return userData; } /** * 引数の文字列をLong型に変換する * @param id ID * @return Long型のID */ private Long stringToLong(String id){ try{ return Long.parseLong(id); }catch(NumberFormatException ex){ return null; } } } |
さらに、検索用Formのエラーメッセージを下記プロパティファイルに追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #メッセージ 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)より大きくなっています。 #フィールド名 name=名前 sex=性別 checked=確認チェック |
また、一覧画面から検索画面に戻れるよう、下記HTMLファイルのsubmitタグの内容を変更している。
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 | <!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.id}__'})}">更新</a></td> <td><a href="/delete_confirm" th:href="@{/delete_confirm(id=${'__${obj.id}__'})}">削除</a></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> |
また、完了画面に表示するボタン名を変更している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!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> |
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-search-2/demo
要点まとめ
- 検索機能を行うSQL文のような動的SQL文を生成するには、MyBatis提供のifタグによる条件分岐を利用すると便利である。