본문 바로가기
Back-end/Spring

[Spring] chapter12 애플리케이션 만들기(애플리케이션 레이어)

by na1-4an 2023. 8. 8.

아래 글은 스프링 프레임 워크 첫걸음 책을 기반하여 작성한 글입니다.

드디어!! 이 책의 마지막 챕터이다!

12-1 애플리케이션 레이어

(1) 작성할 내용 확인

No 레이어 컴포턴트 이름 비고
1 애플리케이션 레이어 View - 화면 표시
2 애플리케이션 레이어 Controller Quizcontroller 제어 역할 담당
3 애플리케이션 레이어 Form QuizForm 화면의 게임 폼을 표현
4 도메인 레이어 Service QuizService 인터페이스로 생성
5 도메인 레이어 ServiceImpl QuizServiceImpl Service를 구현
6 도메인 레이어 도메인 객체 Quiz 엔티티 역할
7 도메인 레이어 Repository QuizRepository 인터페이스로 생성
8 인프라스트럭처 레이어 RepositoryImpl - O/R Mapper로 자동 생성
9 인프라스트럭처 레이어 O/R Mapper - 스프링 데이터 JDBC를 사용

위의 표는 chapter09에서 작성한 이 프로젝트에서 필요한 컴포넌트 목록이다.

이번 장에서는 1-3 컴포넌트를 만들어보겠다.

View에서는 아래처럼 세 개의 HTML파일을 만들겠다.

  1. crud.html: 등록/변경/삭제/참조 화면
  2. play.html: 퀴즈를 랜덤으로 표시하는 화면
  3. answer.html: 해답 화

12-2 애플리케이션 레이어 만들기(목록 표시)

(1) Form 생성

quiz아래에 form 패키지를 만들고, 그 안에 Form 클래스를 아래와 같이 작성한다.

package com.example.quiz.form;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/** Form */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QuizForm {
    /** 식별 ID */
    private Integer id;
    
    /** 퀴즈 내용 */
    @NotBlank
    private String question;
    
    /** 퀴즈 해답 */
    private Boolean answer;
    
    /** 작성자 */
    @NotBlank
    private String author;
    
    /** 등록 또는 변경 판단용*/
    private Boolean newQuiz;

}
@NoArgsConstructor 파라미터가 없는 기본 생성자를 생성
@AllArgsConstructor 모든 필드 값을 파라미터로 받는 생성자를 만듦

등록일 때는 newQuiz의 값이 true, 변경일 떄는 newQuiz의 값이 false이다.

 

(2) Controller 생성

controller패키지를 만들고 그 안에 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;

/** Quiz 컨트롤러 */
@Controller
@RequestMapping("/quiz")
public class QuizController {
    /** DI 대상 */
    @Autowired
    QuizService service;

    /** form-backing bean의 초기화 */
    @ModelAttribute
    public QuizForm setupForm(){
        QuizForm form = new QuizForm();
        //라디오 버튼의 초깃값 설정
        form.setAnswer(true);
        return form;
    }

    /** Quiz 목록 표시 */
    @GetMapping
    public String showList(QuizForm quizForm, Model model){
            //신규 등록 설정
            quizForm.setNewQuiz(true);

            //퀴즈 목록 취득
            Iterable<Quiz> List = service.selectAll();

            //표사용 모델에 저장
            model.addAttribute("list", "list");
            model.addAttribute("title", "등록 폼");
            
            return "crud";

        }   

}

@ModelAttribute: 사용자가 요청시 전달하는 값을 오브젝트 형태로 매핑해주는 어노테이션

quizForm.setNewQuiz(true)를 설정해서 등록 화면을 표시한다.

 

(3) crud.html 생성

templates 폴더 안에 crud.html 파일을 만들어 아래처럼 코드를 채운다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>OX 퀴즈 애플리케이션:CRUD</title>
</head>
<body>
<h1>OX 퀴즈 애플리케이션:CRUD</h1>
<h3 th: text="${title}">제목</h3>
<!-- /* 등록/변경 완료 메시지 */-->
<p th:if="${complete}" th:text="${complete}" style="color:blue"></p>
<!-- /* ### Form ### */ -->
<form method="POST"
    th:action="${quizForm.newQuiz}? @{/quiz/insert} : @{/quiz/update}"
    th:object="${quizForm}">
    <label>퀴즈 내용: </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>퀴즈 정답: </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>작성자: </label>
    <br>
    <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="송신">
</form>
<!-- /* ### Form 끝 ### */-->
<br>
<!-- /* 여기까지가 상부영역 */ -->
<hr>


<!-- /* 여기부터가 하부영역 */ -->
<!-- /* ### 신규 등록할 때만 표시하는 부분 ###/-->
<div th:if="${quizForm.newQuiz}" style="margin: 10px">
    <h3>등록된 퀴즈 목록 <a th:href="@{/quiz/play}">플레이</a><br></h3>
    <!-- 삭제 완료 메시지 */ -->
    <p th:if="${delcomplete}" th:text="${delcomplete}" style="color: blue"></p>
    <p th:if="${msg}" th:text="${msg}" style="color: blue"></p>
    <!-- /* ### 퀴즈 정보가 있으면 표시 ###/-->
    <table border="1" th:unless="${#lists.isEmpty(list)}"
        style="table-layout: fixed;">
        <tr>
            <th>ID</th>
            <th>내용</th>
            <th>해답</th>
            <th>작성자</th>
            <th>변경</th>
            <th>삭제</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 method="GET" th:action="@{/quiz/{id}(id=${obj.id})}">
                    <input type="submit" value="변경">
                </form>
            </td>
            <!-- /* 삭제 버튼 */ -->
            <td>
                <form method="post" th:action="@{/quiz/delete}">
                    <input type="hidden" name="id" th:value="${obj.id}">
                    <input type="submit" value="삭제">
                </form>
            </td>
        </tr>
    </table>
    <!-- /* ### 퀴즈 정보가 없으면 표시 ###/-->
    <p th:if="${#lists.isEmpty(list)}">등록된퀴즈가 없습니다.</p>
</div>
<!-- /* ### 신규 등록이 아닐 때 표시 ###/-->
<p th:unless="${quizForm.newQuiz}">
    <a href="#" th:href="@{/quiz}">CRUD 화면에 돌아가기</a>
</p>
</body>
</html>

th:object="${quizForm}"은 폼이 서버로 전송될 때 사용되는 객체를 지정한다.

우왕.. 아래에서 th: text를 띄어썼더니 오류가 났다.

<h3 th: text="${title}">제목</h3>

다시 고치고 실행시켰더니 아래와 같은 결과가 나왔다.


12-3 애플리케이션 레이어 만들기(등록/변경/삭제 기능)

(1) 등록 기능 만들기

 

 

(2) 변경 기능 만들기

 

 

(3) 삭제 기능 만들기

 

 


12-4 애플리케이션 레이어 만들기(게임 기능)

(1) play.html 생성

 

 

(2) answer.html 생성

 

 

(3) 게임 기능 작성