[코드로 배우는 스프링부트 웹 프로젝트] - 프로젝트 구조 만들기(1): 시작페이지와 Entity 생성

Jongwon·2022년 12월 26일
0

프로젝트는 간단한 방명록 페이지를 만드는 것입니다.

프로젝트는 Spring Boot, War 패키징 방식, 라이브러리는 Spring Boot Devtools, Lombok, Spring Web, Thymeleaf, Spring Data JPA를 사용합니다.

build.gradle의 Dependency 설정에 아래와 같이 작성합니다.

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
	testImplementation('org.springframework.boot:spring-boot-starter-test')
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
	implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client'
}

application.properties도 아래와 같이 작성합니다.

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3308/bootex
spring.datasource.username=bootuser
spring.datasource.password=bootuser

spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true


spring.thymeleaf.cache=false

이제 기본 설정은 끝이 났습니다. 다음은 기본 페이지를 만들겠습니다.
1. 기본 페이지 템플릿은 BootStrap의 Simple Sidebar를 이용할 예정입니다. 해당 링크에서 파일을 다운받은 뒤, js, css, assets 폴더를 static폴더에 추가하시면 됩니다.

  1. static.template 폴더에 layout 폴더를 만들고 basic.html파일을 생성합니다.

  2. BootStrap에서 다운받았던 html 코드를 붙여넣기 해줍니다.

  3. 타임리프 적용을 위해 가장 위의 부분을 아래와 같이 수정합니다.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:fragment="setContent(content)">
<head>
  1. Head 내부의 CSS 관련 코드도 타임리프 링크로 수정합니다.
    <title>Simple Sidebar - Start Bootstrap Template</title>
    <!-- Favicon-->
    <link rel="icon" type="image/x-icon" th:href="@{/assets/favicon.ico}" />
    <!-- Core theme CSS (includes Bootstrap)-->
    <link th:href="@{/css/styles.css}" rel="stylesheet" />
  1. 아래의 Script도 타임리프 링크로 수정 후, Head 내부로 옮깁니다. 다른 html파일에서도 이 basic.html을 사용할 예정이므로 다른 코드들보다 앞에 있어야합니다. 또한 bootstrap 버전 5에는 빠진 jQuery를 뒤에 있을 코드를 위해 추가합니다.
<!-- Favicon-->
<link rel="icon" type="image/x-icon" th:href="@{/assets/favicon.ico}" />
<!--jQuery-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- Core theme JS-->
<script th:src="@{/js/scripts.js}"></script>
<!-- Core theme CSS (includes Bootstrap)-->
<link th:href="@{/css/styles.css}" rel="stylesheet" />
<!-- Bootstrap core JS-->
<script th:src="@{https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js}"></script>

jQuery는 bootstrap.min.js보다 앞에서 스크립트 선언이 되어야 인식됩니다.

  1. 마지막에 </th:block>으로 닫아줍니다.
</div>
</body>
</th:block>
</html>
  1. body태그의 가장 아래에 있는 page content부분을 아래와 같이 수정합니다. 해당 부분이 다른 html 코드로 대체되는 부분입니다.
<!-- Page content-->
<div class="container-fluid">
      <th:block th:replace="${content}"></th:block>
</div>
  1. templates아래에 guestbook 폴더를 만들고, list.html을 생성합니다.
  2. 아래의 코드를 작성합니다.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<th:block th:replace="~{/layout/basic::setContent(~{this::content})}">
    <th:block th:fragment="content">
        <h1>GuestBook List Page</h1>
    </th:block>
</th:block>
  1. src 폴더에 controller 패키지를 생성하고, GuestBookController를 생성합니다.

  2. 아래의 코드를 작성합니다.

package org.zerock.guestbook.controller;

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@Log4j2
@RequestMapping("/guestbook")
public class GuestBookController {

    @GetMapping({"/", "/list"})
    public String list() {
        log.info("list.........");

        return "/guestbook/list";
    }
}

localhost:8080/guestbook에 접속했을 때 다음과 같은 페이지가 만들어졌다면 성공입니다.

다음은 BaseEntity를 생성하는 것입니다. 데이터 등록 시간과 마지막 수정시간을 여러 엔티티에서 사용할텐데, 이를 할때마다 계산하기엔 번거롭기 때문에 따로 BaseEntity를 생성한 뒤, 이를 상속받아 사용할 예정입니다.

package org.zerock.guestbook.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@MappedSuperclass
@EntityListeners(value = {AuditingEntityListener.class})
@Getter
abstract class BaseEntity {

    @CreatedDate
    @Column(name="regdate", updatable = false)
    private LocalDateTime regDate;

    @LastModifiedDate
    @Column(name="moddate")
    private LocalDateTime modDate;
}

@MappedSuperClass는 해당 클래스가 엔티티 클래스가 아니고, 단순히 자식 엔티티에게 매핑 정보만 제공할 것임을 알려주는 어노테이션입니다.

참고자료: https://ict-nroo.tistory.com/129

다음의 @EntityListeners 어노테이션을 이해하려면 Spring JPA의 동작과정을 알아야합니다. 아래의 링크에서 JPA에 대한 설명이 잘되어 있으니 참고하시면 좋습니다. 간단하게, JPA는 DB와 서버 사이에 영속성 컨텍스트(Persistence Context)라는 1차 캐시의 역할을 하는 컨텍스트를 배치하는데, 엔티티의 변화를 리스너를 통해 감지한 뒤 value로 준 리스너 클래스의 메서드들이 실행됩니다. 그 중에서 AuditingEntityListener는 엔티티의 Create와 Update를 인식하여 regdate와 moddate에 적절한 값을 지정해줍니다.

참고자료: https://developer-pi.tistory.com/307?category=1036893

AuditingEntityListener를 사용하기 위해서는 프로젝트에 @EnableJpaAuditing을 추가해야 합니다.
GuestbookApplication 파일을 아래와 같이 수정합니다.

@SpringBootApplication
@EnableJpaAuditing
public class GuestbookApplication {

	public static void main(String[] args) {
		SpringApplication.run(GuestbookApplication.class, args);
	}
}

다음으론 새로운 repository 패키지를 만들어 GuestBookRepository 자바 파일을 생성합니다.

package org.zerock.guestbook.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.zerock.guestbook.entity.Guestbook;

public interface GuestbookRepository extends JpaRepository<Guestbook, Long> {

}

위와 같이 JpaRepository를 상속받게 하여 스프링빈에 등록합니다.

profile
Backend Engineer

0개의 댓글