728x90
퀴즈를 CRUD하고 문제를 풀 수 있는 어플리케이션 레이어를 구현한다.
//QuizForm
package com.example.quiz.form;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QuizForm {
private Integer id;
@NotBlank
private String question;
private Boolean answer;
@NotBlank
private String author;
private Boolean newQuiz;
}
@NotBlank는 빈 값을 허용하지 않는 유효성 검사 어노테이션이고 퀴즈 생성/변경을 확인할 수 있도록 boolean값인 newQuiz 변수도 만들어준다.
//QuizController
package com.example.quiz.controller;
import com.example.quiz.entity.Quiz;
import com.example.quiz.form.QuizForm;
import com.example.quiz.service.QuizService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/quiz")
public class QuizController {
@Autowired
QuizService service;
@ModelAttribute
public QuizForm setUpForm() {
QuizForm form = new QuizForm();
form.setAnswer(true);
return form;
}
@GetMapping
public String showList(QuizForm quizForm, Model model) {
quizForm.setNewQuiz(true);
Iterable<Quiz> list = service.selectAll();
model.addAttribute("list", list);
model.addAttribute("title", "Registration form");
return "crud";
}
}
/quiz로 끝나는 url에 대해 해당 클래스의 요청 핸들러 메서드를 호출한다.
위의 컨트롤러에 의해 다음과 같은 페이지가 반환된다.
<!--crud.html-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>CRUD</title>
</head>
<body>
<h1>OX QUIZ APPLICATION</h1>
<h3 th:text="${title}"></h3>
<p th:if="${complete}" th:text="${complete}" style="color:blue"></p>
<form method="POST"
th:action="${quizForm.newQuiz}? @{/quiz/insert} : @{/quiz/update}"
th:object="${quizForm}">
<label>QUIZ: </label>
<br>
<textarea rows="5" cols="50" th:field="*{question}"></textarea>
<br>
<div th:if="${#fields.hasErrors('question')}" th:errors="*{question}"
style="color:red"></div>
<label>ANSWER: </label>
<br>
<input type="radio" value="true" th:field="*{answer}"> O
<input type="radio" value="false" th:field="*{answer}"> X
<br>
<div th:if="${#fields.hasErrors('answer')}" th:errors="*{answer}"
style="color:red"></div>
<label>AUTHOR: </label>
<input type="text" th:field="*{author}" />
<br>
<div th:if="${#fields.hasErrors('author')}" th:errors="*{author}"
style="color:red"></div>
<input th:if="${id}" type="hidden" th:field="*{id}">
<input type="submit" value="SUBMIT">
</form>
<br>
<hr>
<div th:if="${quizForm.newQuiz}" style="margin:10px">
<h3>REGISTERED QUIZ LIST <a th:href="@{/quiz/play}">PLAY</a><br></h3>
<p th:if="${delcomplete}" th:text="${delcomplete}" style="color:blue"></p>
<p th:if="${msg}" th:text="${msg}" style="color:red"></p>
<table border="1" th:unless="${#lists.isEmpty(list)}" style="table-layout:fixed">
<tr>
<th>ID</th>
<th>CONTENT</th>
<th>ANSWER</th>
<th>AUTHOR</th>
<th>UPDATE</th>
<th>DELETE</th>
</tr>
<tr th:each="obj : ${list}" align="center">
<td th:text="${obj.id}"></td>
<td th:text="${obj.question}" align="left"></td>
<td th:text="${obj.answer} == true?'O':'X'"></td>
<td th:text="${obj.author}"></td>
<td>
<form th:action="@{/quiz/{id}(id=${obj.id})}" method="get">
<input type="submit" value="UPDATE">
</form>
</td>
<td>
<form th:action="@{/quiz/delete}" method="post">
<input type="hidden" name="id" th:value="${obj.id}">
<input type="submit" value="DELETE">
</form>
</td>
</tr>
</table>
<p th:if="${#lists.isEmpty(list)}">NO REGISTERED QUIZ</p>
</div>
<p th:unless="${quizForm.newQuiz}">
<a href="#" th:href="@{/quiz}">BACK TO CRUD</a>
</p>
</body>
</html>
다음은 퀴즈를 CUD 하는 기능을 작성한다.
// QuizController
@PostMapping("/insert")
public String insert(@Validated QuizForm quizForm, BindingResult bindingResult,
Model model, RedirectAttributes redirectAttributes) {
Quiz quiz = new Quiz();
quiz.setQuestion(quizForm.getQuestion());
quiz.setAnswer(quizForm.getAnswer());
quiz.setAuthor(quizForm.getAuthor());
if (!bindingResult.hasErrors()) {
service.insertQuiz(quiz);
redirectAttributes.addFlashAttribute("complete", "QUIZ REGISTERED");
return "redirect:/quiz";
} else {
return showList(quizForm, model);
}
}
//QuizController
@GetMapping("/{id}")
public String showUpdate(QuizForm quizForm, @PathVariable Integer id, Model model) {
Optional<Quiz> quizOpt = service.selectOneById(id);
Optional<QuizForm> quizFormOpt = quizOpt.map(t -> makeQuizForm(t));
if (quizFormOpt.isPresent()) {
quizForm = quizFormOpt.get();
}
makeUpdateModel(quizForm, model);
return "crud";
}
private void makeUpdateModel(QuizForm quizForm, Model model) {
model.addAttribute("id", quizForm.getId());
quizForm.setNewQuiz(false);
model.addAttribute("quizForm", quizForm);
model.addAttribute("title", "UPDATE FORM");
}
@PostMapping("/update")
public String update(
@Validated QuizForm quizForm,
BindingResult result,
Model model,
RedirectAttributes redirectAttributes) {
Quiz quiz = makeQuiz(quizForm);
if (!result.hasErrors()) {
service.updateQuiz(quiz);
redirectAttributes.addFlashAttribute("complete", "QUIZ UPDATED");
return "redirect:/quiz" + quiz.getId();
} else {
makeUpdateModel(quizForm, model);
return "crud";
}
}
private Quiz makeQuiz(QuizForm quizForm) {
Quiz quiz = new Quiz();
quiz.setId(quizForm.getId());
quiz.setQuestion(quizForm.getQuestion());
quiz.setAnswer(quizForm.getAnswer());
quiz.setAuthor(quizForm.getAuthor());
return quiz;
}
private QuizForm makeQuizForm(Quiz quiz) {
QuizForm form = new QuizForm();
form.setId(quiz.getId());
form.setQuestion(quiz.getQuestion());
form.setAnswer(quiz.getAnswer());
form.setAuthor(quiz.getAuthor());
form.setNewQuiz(false);
return form;
}
//QuizController
@PostMapping("/delete")
public String delete(
@RequestParam("id") String id,
Model model,
RedirectAttributes redirectAttributes) {
service.deleteQuizById(Integer.parseInt(id));
redirectAttributes.addFlashAttribute("delcomplete", "QUIZ DELETED");
return "redirect:/quiz";
}
이제 OX 퀴즈를 즐길 수 있는 화면과 기능을 구성한다.
<!--play.html-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>OX QUIZ PLAY</title>
</head>
<body>
<h1>OX QUIZ APPLICATION:PLAY</h1>
<h3>QUIZ</h3>
<th:block th:if="${msg}">
<p th:text="${msg}" style="color:red"></p>
<a th:href="@{/quiz/}">BACK TO CRUD</a>
</th:block>
<th:block th:unless="${msg}">
<p th:text="${quizForm.question}">QUIZ</p>
<form th:action="@{/quiz/check}" th:object="${quizForm}" method="POST">
<input type="hidden" th:field="*{id}">
<button name="answer" value="true">O</button>
<button name="answer" value="false">X</button>
</form>
</th:block>
</body>
</html>
msg의 유무에 따라 문제의 표시 여부를 결정한다.
<!--answer.html-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>RESULT</title>
</head>
<body>
<h1>RESULT</h1>
<h2 th:text="${msg}" th:style="'color:' + (${msg} == 'CORRECT' ? 'green' : 'red')"></h2>
<a th:href="@{/quiz/play}">REPLAY</a>
<a th:href="@{/quiz}">BACK TO CRUD</a>
</body>
</html>
msg의 내용에 따라 글자의 색을 결정하는 삼항연산자를 이용해봤다.
//QuizController
@GetMapping("/play")
public String showQuiz(QuizForm quizForm, Model model) {
Optional<Quiz> quizOpt = service.selectOneRandomQuiz();
if(quizOpt.isPresent()) {
Optional<QuizForm> quizFormOpt = quizOpt.map(t -> makeQuizForm(t));
quizForm = quizFormOpt.get();
} else {
model.addAttribute("msg", "NO REGISTERED QUIZ");
return "play";
}
model.addAttribute("quizForm", quizForm);
return "play";
}
@PostMapping("/check")
public String checkQuiz(QuizForm quizForm, @RequestParam Boolean answer, Model model) {
if (service.checkQuiz(quizForm.getId(), answer)) {
model.addAttribute("msg", "CORRECT");
} else {
model.addAttribute("msg", "WRONG");
}
return "answer";
}
728x90
'웹 > Spring, Django' 카테고리의 다른 글
[Spring]Service (1) | 2023.05.15 |
---|---|
[Spring]Application-CRUD (0) | 2023.05.12 |
[Spring]Request Parameter/Validation (0) | 2023.05.11 |
[Spring]Thymeleaf 문법, Layout (0) | 2023.05.10 |
[Spring]JDBC/MVC Model (0) | 2023.05.09 |
댓글