git을 잘못 사용해서 기존에 했던 작업물들이 모두 사라졌다..
![](https://t1.daumcdn.net/keditor/emoticon/friends2/large/006.png)
github에 올려두었던 코드들을 다시 clone해올까도 했지만, 어차피 폴더 구조도 변경해야 하고, JPA와 REST API를 적용하도록 코드를 변경해야 해서 그냥 처음부터 다시 만들기로 결정했다.
그래서 다시 프로젝트를 생성하러 Spring Initializr에 들어갔다..
- Project: Gradle Project
- Language: Java
- Spring Boot: 2.6.5
- Project Metadata
- Group: board
- Artifact: plming
- Name: plming
- package name: plming
- Packaging: Jar
- Dependencies
- Spring Boot DevTools
- Lombok
- Spring Configuration Processor
- Spring Data JPA
- MyBatis Framework
- MySQL Driver
- Thymeleaf
- Spring Web
나머지 프로젝트 설정과 데이터베이스 연동과 관련된 설정은 이 포스팅을 참고하면 된다,
1. DB 설정
"main/resource"의 application.properties에 아래 코드를 추가한다. username과 password를 각자 설정에 맞게 수정한다.
# 데이터 소스 (Data Source)
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/board?serverTimezone=Asia/Seoul&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.hikari.username=root
spring.datasource.hikari.password=1111
# Resource and Thymeleaf Refresh
spring.devtools.livereload.enabled=true
spring.thymeleaf.cache=false
# JPA Properties
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=none
spring.jpa.open-in-view=false
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
그다음으로 데이터베이스 관련 Configuration 클래스를 생성한다. "main.java.plming" 패키지 밑에 "config" 패키지를 생성하고, DatabaseConfig 클래스를 추가한다. 클래스 생성이 완료되면 클래스에 아래 코드를 추가한다.
package plming.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariConfig hikariConfig() {
return new HikariConfig();
}
@Bean
public DataSource dataSource() {
return new HikariDataSource(hikariConfig());
}
}
2. Entity 클래스 생성하기
plming 패키지 아래 board 패키지를 생성하고 board 패키지 아래 entity 패키지를 추가한 다음 Board 클래스를 추가한다.
Board 클래스 생성이 완료되면 더보기 코드를 작성한다.
package plming.board.entity;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // PK
@Column(columnDefinition = "varchar")
private String user; // 사용자
@Column(columnDefinition = "enum")
private String category; // 카테고리
@Column(columnDefinition = "enum")
private String status; // 모집 상태
@Column(columnDefinition = "varchar")
private String period; // 진행 기간
@Column(columnDefinition = "varchar")
private String title; // 제목
@Column(columnDefinition = "varchar")
private String content; // 내용
@Column(columnDefinition = "Integer")
private Integer participantNum = 0;
@Column(columnDefinition = "bigint")
private Long viewCnt = 0L;
@Column(columnDefinition = "datetime")
private LocalDateTime createDate = LocalDateTime.now();
@Column(columnDefinition = "datetime")
private LocalDateTime updateDate;
@Column(columnDefinition = "enum")
private char deleteYn = 'N';
@Builder
public Board(String user, String category, String status, String period, String title, String content) {
this.user = user;
this.category = category;
this.status = status;
this.period = period;
this.title = title;
this.content = content;
}
}
애노테이션 | 설명 |
@Getter | 해당 클래스에 포함된 멤버 변수의 모든 getter 메서드를 생성해주는 롬복 |
@NoArgsConstructor (access = AccessLevel.PROTECTED) |
해당 클래스의 기본 생성자를 생성해 주는 어노테이션이다. access 속성을 이용해 동일한 패키지 내의 클래스에서만 객체를 생성할 수 있도록 제어한다. |
@Entity | 해당 클래스가 테이블과 매핑되는 JPA의 Entity 클래스임을 의미한다. 기본적으로 클래스명(Camel Case)을 테이블명(Snake Case)으로 매핑한다. 혹시라도 클래스명과 테이블명이 다를 수 밖에 없는 상황에서는 클래스 레벨에 @Table을 선언하고, @Table(name = "user")과 같이 name 속성을 이용해서 처리하면 된다. |
@Id | 해당 멤버가 Entity의 PK임을 읨미한다. 일반적으로 MySQL DB는 PK를 bigint 타입으로, Entity에서는 Long 타입으로 선언한다고 한다. |
@GeneratedValue (strategy = GenerationType.IDENTITY) |
PK 생성 전략을 설정하는 어노테이션이다. MySQL은 자동 증가(AUTO_INCREMENT)를 지원하는 DB이며, PK 자동 증가를 지원하는 DB는 해당 어노테이션을 선언해야 한다. 오라클과 같이 Sequence를 이용하는 DB는 GenerataionType.SEQUENCE를 이용해야 한다. GenerationType.AUTO로 설정하게 되면 DB에서 제공하는 PK 생성 전략을 가져가게 된다. |
@Builder | 롬복에서 제공해주는 기능으로 생성자 대신 이용하는 패턴이다. |
@Setter가 없음 | Entity 클래스는 테이블 그 자체이미로, 각각의 멤버 변수는 해당 테이블의 컬럼이라는 의미가 되고, 컬럼에 대한 setter를 무작정 생성하는 경우, 객체의 값이 어느 시점에 변경되었는지 알 수 없기 때문에, Entity클래스에는 절대로 Set 메서드가 존재해서는 안된다. |
3. JPA Repository 인터페이스 생성하기
"board.entity" 패키지에 BoardRepository 인터페이스를 추가한 뒤 JpaRepository 인터페이스를 상속받는다.
package plming.board.entity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BoardRepository extends JpaRepository<Board, Long> {
}
Repository는 MyBatis의 SQL Mapper와 유사한 퍼시스턴스 영역에 사용되는 인터페이스이다. Entity 클래스와 Repository 인터페이스는 반드시 같은 패키지에 위치해야 한다.
- extends JpaRepository<Board, Long>
- Repository 인터페이스에서 JpaRepository 인터페이스를 상속받을 때 Entity 클래스의 타입(Board)과 PK에 해당하는 데이터 타입(Long)을 선언하면 해당 Entity 클래스와 매핑되는 테이블인 board 테이블의 CRUD 기능을 사용할 수 있다.
4. CRUD 테스트하기
JUnit을 이용해서 테스트해볼 것이다.
"test.java" 디렉터리의 plming 패키지 아래 board 패키지와 BoardTest 클래스를 추가하고, 아래 더보기 코드를 작성한다.
package plming.board;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import plming.board.entity.Board;
import plming.board.entity.BoardRepository;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class BoardTest {
@Autowired
BoardRepository boardRepository;
@Test
void save() {
// given
Board post = Board.builder()
.title("1번 게시글 제목")
.category("스터디")
.content("CRUD 테스트 입니다.")
.period("하루")
.status("모집 중")
.user("사용자1")
.build();
// when
boardRepository.save(post);
// then
Board postCp = boardRepository.findById(post.getId()).get();
assertThat(postCp.getTitle()).isEqualTo(post.getTitle());
assertThat(postCp.getContent()).isEqualTo(post.getContent());
assertThat(postCp.getUser()).isEqualTo(post.getUser());
}
@Test
void findAll() {
// when
List<Board> boardList = boardRepository.findAll();
// then
assertEquals(boardRepository.count(), boardList.size());
}
@Test
void delete() {
// given
Board post = boardRepository.findById(1L).get();
// when
boardRepository.delete(post);
// then
assertEquals(0, boardRepository.count());
}
}
테스트 메서드를 하나씩 돌려보면 모두 성공하는 것을 확인할 수 있다.
코드를 살펴보면
@SpringBootTest | 스프링 부트는 해당 어노테이션만 선언하면 테스팅이 가능하다. |
boardRepository | 스프링 컨테이너에 등록된 BoardRepository 객체(Bean)를 주입받는다. |
save() | 게시글 저장에 이용되는 post는 Builder 패턴을 통해 생성된 객체이다. 생성자와는 달리, Builder 패턴을 이용하면 어떤 멤버에 어떤 값을 세팅하는지 직관적으로 확인이 가능하다. 생성자의 경우 객체를 생성할 때 인자의 순서에 영향을 받지만, Builder 패턴은 인자의 순서에 관계없이 객체를 생성할 수 있다. |
findAll() | boardRepository의 count()와 findAll() 메서드를 이용해서 전체 게시글 수와 전체 게시글 리스트를 조회하는 쿼리를 실행한다. |
delete() | boardRepository의 findById() 메서드를 이용해서 해당 Entity를 조회한다. findById()는 JPA에서 기본으로 제공해주는 메서드로, Entity의 PK를 기준으로 데이터를 조회한 다음 delete() 메서드를 실행해 게시글을 삭제한다. findById()의 리턴 타입은 Optional<T>라는 클래스이다. Optional은 반복적인 NULL 처리를 피하기 위해 자바 8에서 최초로 도입된 클래스이다. |
본 프로젝트는 아래 블로그를 참고해서 만들었습니다.
https://congsong.tistory.com/51?category=749196
'Spring Boot Project > Plming' 카테고리의 다른 글
[Plming] 게시글 등록 / 수정 구현하기 (0) | 2022.03.29 |
---|---|
[Plming] 게시판 예외 처리(Global Exception Handling) 알아보기 (0) | 2022.03.29 |
[Plming] 게시글 등록 기능에 REST API 적용하기 (0) | 2022.03.28 |
[Plming] 게시글 등록 구현하기 (0) | 2022.03.26 |
[Plming] 게시판 CRUD 처리하기 (0) | 2022.03.25 |
댓글