前提
Java、webアプリケーション初学者です。
周りに聞ける人がいないのでこちらで投稿させていただきました。
まだクラス間の流れを追っていくので精一杯の段階です。
「SpringFramework 超入門 やさしくわかるwebアプリ開発」樹下雅章氏 著
のテキストを読み進めながら、12章の最後まで実際にコードを入力し、動かしているのですが
狙った通りに動かないので原因を探っています。
理解が追い付いていないのはわかっているのですが、問題解決に向けてどこをみていけばよいのか等
アドバイスを頂けると大変助かります。
実現したいこと
- Web上のボタンでデータの更新を行えるようしたい
発生している問題・エラーメッセージ
エラーメッセージはありません。
元のデータを更新したいが、実際には新しくデータが追加され、元あったデータが残ってしまいます。
以下、原因の部分がありそうなクラスファイルのソースを貼りました。
該当のソースコード
java
1package com.example.quiz.entity; 2 3import org.springframework.data.annotation.Id; 4 5import lombok.AllArgsConstructor; 6import lombok.Data; 7import lombok.NoArgsConstructor; 8 9/** quizテーブル用:Entity */ 10@Data 11@NoArgsConstructor 12@AllArgsConstructor 13public class Quiz { 14 /** 識別ID */ 15 @Id 16 private Integer id; 17 /** クイズの内容 */ 18 private String question; 19 /** クイズの解答 */ 20 private Boolean answer; 21 /** 作成者 */ 22 private String author; 23} 24package com.example.quiz.service; 25 26import java.util.Optional; 27 28import com.example.quiz.entity.Quiz; 29 30public interface QuizService { 31 /** クイズ情報を全件取得する */ 32 Iterable<Quiz> selectAll(); 33 /** クイズ情報を、idをキーに1件取得します */ 34 Optional<Quiz> selectOneById(Integer id); 35 /** クイズ情報をランダムに取得します */ 36 Optional<Quiz> selectOneRandomQuiz(); 37 /** クイズの正解/不正解を判定します */ 38 Boolean checkQuiz(Integer id,Boolean myAnswer); 39 /** クイズを登録します */ 40 void insertQuiz(Quiz quiz); 41 /** クイズ更新します */ 42 void updateQuiz(Quiz quiz); 43 /** クイズを削除します */ 44 void deleteQuizById(Integer id); 45} 46 47package com.example.quiz.controller; 48 49import java.util.Optional; 50 51import org.springframework.beans.factory.annotation.Autowired; 52import org.springframework.stereotype.Controller; 53import org.springframework.ui.Model; 54import org.springframework.validation.BindingResult; 55import org.springframework.validation.annotation.Validated; 56import org.springframework.web.bind.annotation.GetMapping; 57import org.springframework.web.bind.annotation.ModelAttribute; 58import org.springframework.web.bind.annotation.PathVariable; 59import org.springframework.web.bind.annotation.PostMapping; 60import org.springframework.web.bind.annotation.RequestMapping; 61import org.springframework.web.bind.annotation.RequestParam; 62import org.springframework.web.servlet.mvc.support.RedirectAttributes; 63 64import com.example.quiz.entity.Quiz; 65import com.example.quiz.form.QuizForm; 66import com.example.quiz.service.QuizService; 67 68/** Quizコントローラ */ 69@Controller 70@RequestMapping("/quiz") 71public class QuizController { 72 /** DI対象 */ 73 @Autowired 74 QuizService service; 75 /** 「from-backing bean」の初期化 */ 76 @ModelAttribute 77 public QuizForm setUpForm() { 78 QuizForm form = new QuizForm(); 79 // ラジオボタンのデフォルト値設定 80 form.setAnswer(true); 81 return form; 82 } 83 /** Quizの一覧を表示します */ 84 @GetMapping 85 public String showList(QuizForm quizForm,Model model) { 86 // 新規登録設定 87 quizForm.setNewQuiz(true); 88 // 掲示板の一覧を取得する 89 Iterable<Quiz> list = service.selectAll(); 90 // 表示用「Model」への格納 91 model.addAttribute("list",list); 92 model.addAttribute("title","登録用フォーム"); 93 return "crud"; 94 } 95 /** Quizデータを1件挿入 */ 96 @PostMapping("/insert") 97 public String insert(@Validated QuizForm quizForm,BindingResult bindingResult,Model model,RedirectAttributes redirectAttributes) { 98 // FormからEntityへの詰め替え 99 Quiz quiz = new Quiz(); 100 quiz.setQuestion(quizForm.getQuestion()); 101 quiz.setAnswer(quizForm.getAnswer()); 102 quiz.setAuthor(quizForm.getAuthor()); 103 // 入力チェック 104 if (!bindingResult.hasErrors()) { 105 service.insertQuiz(quiz); 106 redirectAttributes.addFlashAttribute("complete","登録が完了しました"); 107 return "redirect:/quiz"; 108 }else { 109 // エラーがある場合は、一覧表示処理を呼びます 110 return showList(quizForm,model); 111 } 112 } 113 /** Quizデータを1件取得し、フォーム内に表示する */ 114 @GetMapping("/{id}") 115 public String showUpdate(QuizForm quizForm,@PathVariable Integer id,Model model) { 116 //Quizを取得(Optionalでラップ) 117 Optional<Quiz> quizOpt = service.selectOneById(id); 118 //QuizFormへの詰め直し 119 Optional<QuizForm> quizFormOpt = quizOpt.map(t -> makeQuizForm(t)); 120 //QuizFormがnullでなければ中身を取り出す 121 if(quizFormOpt.isPresent()) { 122 quizForm = quizFormOpt.get(); 123 } 124 //更新用のModelを作成する 125 makeUpdateModel(quizForm,model); 126 return "crud"; 127 } 128 /** 更新用のModelを作成する */ 129 private void makeUpdateModel(QuizForm quizForm,Model model) { 130 model.addAttribute("id",quizForm.getId()); 131 quizForm.setNewQuiz(false); 132 model.addAttribute("quizForm",quizForm); 133 model.addAttribute("title","更新用フォーム"); 134 } 135 /** idをkeyにしてデータを更新する */ 136 @PostMapping("/update") 137 public String update( 138 @Validated QuizForm quizForm, 139 BindingResult result, 140 Model model, 141 RedirectAttributes redirectAttributes) { 142 //QuizFormからQuizに詰め直す 143 Quiz quiz = makeQuiz(quizForm); 144 // 入力チェック 145 if(!result.hasErrors()) { 146 //更新処理、フラッシュスコープの使用、リダイレクト(個々の編集ページ) 147 service.updateQuiz(quiz); 148 redirectAttributes.addFlashAttribute("complete","更新が完了しました"); 149 // 更新画面を表示する 150 return "redirect:/quiz/" + quiz.getId(); 151 }else { 152 // 更新用のModelを作成する 153 makeUpdateModel(quizForm,model); 154 return "crud"; 155 } 156 } 157 // ----------【以下はFormとDomainObjectの詰めなおし】---------- 158 /** QuizFormからQuizに詰め直して戻り値とし返します */ 159 private Quiz makeQuiz(QuizForm quizForm) { 160 Quiz quiz = new Quiz(); 161 quiz.setId(quizForm.getId()); 162 quiz.setQuestion(quizForm.getQuestion()); 163 quiz.setAnswer(quizForm.getAnswer()); 164 quiz.setAuthor(quizForm.getAuthor()); 165 return quiz; 166 } 167 /** QuizからQuizFormに詰め直して戻り値とし返します */ 168 private QuizForm makeQuizForm(Quiz quiz) { 169 QuizForm form = new QuizForm(); 170 form.setId(quiz.getId()); 171 form.setQuestion(quiz.getQuestion()); 172 form.setAnswer(quiz.getAnswer()); 173 form.setAuthor(quiz.getAuthor()); 174 form.setNewQuiz(false); 175 return form; 176 } 177crud.html 178<!DOCTYPE html> 179<html xmlns:th="http://www.thymeleaf.org"> 180<head> 181<meta charset="UTF-8"> 182<title>「〇×クイズ」アプリ:CRUD</title> 183</head> 184<body> 185 <h1>「〇×クイズ」アプリ:CRUD</h1> 186 <h3 th:text="${title}">タイトル</h3> 187 <!-- /* 登録・更新完了コメント*/ --> 188 <p th:if="${complete}" th:text="${complete}" style= "color:blue"></p> 189 <!--/* ▼▼▼ Form ▼▼▼ */--> 190 <form method="POST" 191 th:action="${quizForm.newQuiz}? @{/quiz/insert} : @{/quiz/update}" 192 th:object="${quizForm}"> 193 <label>クイズの内容:</label><br> 194 <textarea rows="5" cols="50" th:field="*{question}"></textarea> 195 <br> 196 <div th:if="${#fields.hasErrors('question')}" th:errors="*{question}" 197 style="color:red"></div> 198 <label>クイズの解答</label><br> 199 <input type="radio" value="true" th:field="*{answer}">「〇」 200 <input type="radio" value="false" th:field="*{answer}">「×」 201 <br> 202 <div th:if="${#fields.hasErrors('answer')}" th:errors="*{answer}" 203 style="color:red"></div> 204 <label>作成者:</label><br> 205 <input type="text" th:field="*{author}" /> 206 <br> 207 <div th:if="${#fields.hasErrors('author')}" th:errors="*{answer}" 208 style="color=red"></div> 209 <input th:if="${id}" type="hidden" th:field="${id}"> 210 <input type="submit" value="送信"> 211 </form> 212 <!--/* △△△ Form △△△*/--> 213 <br> 214 <!--/* ========== ここまで上部エリア ========== */--> 215 <hr> 216 <!--/* ========== ここから下部エリア ========== */--> 217 <!--/* ▼▼▼ 新規登録時のみ表示 ▼▼▼ */--> 218 <div th:if="${quizForm.newQuiz}" style="margin: 10px"> 219 <h3>登録クイズ一覧:<a th:href="@{/quiz/play}">プレイ</a><br></h3> 220 <!--/* 削除完了コメント */--> 221 <p th:if="${delcomplete}" th:text="${delcomplete}" style="color:blue"></p> 222 <p th:if="${msg}" th:text="${msg}" style="color:red"></p> 223 <!--/* ▼▼▼ クイズ情報が1件でもあれば表示 ▼▼▼ */--> 224 <table border="1" th:unless="${#lists.isEmpty(list)}" 225 style="table-layout: fixed;"> 226 <tr> 227 <th>ID</th> 228 <th>内容</th> 229 <th>解答</th> 230 <th>作成者</th> 231 <th>編集</th> 232 <th>削除</th> 233 </tr> 234 <tr th:each="obj : ${list}" align="center"> 235 <td th:text="${obj.id}"></td> 236 <td th:text="${obj.question}" align="left"></td> 237 <td th:text="${obj.answer} == true?'〇':'×'"></td> 238 <td th:text="${obj.author}"></td> 239 <!--/* 編集ボタン */--> 240 <td> 241 <form method="GET" th:action="@{/quiz/{id}(id=${obj.id})}"> 242 <input type="submit" value="編集"> 243 </form> 244 </td> 245 <!--/* 削除ボタン */--> 246 <td> 247 <form method="POST" th:action="@{/quiz/delete}"> 248 <input type="hidden" name="id" th:value="${obj.id}"> 249 <input type="submit" value="削除"> 250 </form> 251 </td> 252 </tr> 253 </table> 254 <!--/* △△△ クイズ情報が1件でもあれば表示 △△△ */--> 255 <!--/* ▼▼▼ クイズ情報が1件もない場合表示 ▼▼▼ */--> 256 <p th:if="${#lists.isEmpty(list)}">登録されているクイズはありません。</p> 257 <!--/* △△△ クイズ情報が1件もない場合表示 △△△ */--> 258 </div> 259 <!--/* △△△ 新規登録字のみ表示 △△△ */--> 260 <!--/* ▼▼▼ 新規登録時でない時に表示 ▼▼▼ */--> 261 <p th:unless="${quizForm.newQuiz}"> 262 <a href="#" th:href="@{/quiz}">CRUD画面へ戻る</a> 263 </p> 264 <!--/* △△△ 新規登録時でない時に表示 △△△ */--> 265</body> 266</html>
試したこと
コードのスペルチェック
補足情報(FW/ツールのバージョンなど)
Spring Boot 2.7.5
Eclipse 4.24.0
あなたの回答
tips
プレビュー