Spring Boot JPA 게시판 - CRUD (with MySQL)
Spring Boot 게시판 프로젝트를 시작하기 위해 Database 생성하고 끝냈었다.
MySQL 접속 및 database 생성
MySQL을 Docker 에 설치하였고, Spring boot 와 연동하기 전 database 를 생성해보자. Docker에 MySQL을 설치하는 방법은 아래 글을 참고! (Mac) Docker 에 MySql 설치하기 1. Docker 공식 홈페이지의 가이드를 확..
mkdevlab.tistory.com
게시판에 사용 할 Table 을 만들고, Spring Data JPA 를 이용해서 Create, Read, Delete 를 구현해보자.
오늘은 JUnit 을 이용해서 Table 에 잘 들어가고, 삭제가 되는 지 Test 만 진행해보고자 한다.
그럼 시작 !
0. application.properties 수정
# datasource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mkdevlab?serverTimezone=Asia/Seoul&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=password
# 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
1. Spring Boot 프로젝트 생성
Type : Gradle
Java : 8
Packaging : Jar
Dependency
- Lombok
- Thymeleaf
- MySQL Driver
- Spring Data JPA
- Web
- Spring Security (로그인도 같이 구현할 것이다)
2. 기초 Package 생성
- config
- controller
- domain
- dto
- repository
- service
3. domain - Board Entity 생성
package com.mkdevlab.springbootboard.domain;
import java.time.LocalDateTime;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // PK
private String title;
private String content;
private String writer;
private int hits;
private char deleteYn;
private LocalDateTime createdDate = LocalDateTime.now();
private LocalDateTime modifiedDate;
@Builder
public Board(String title, String content, String writer, int hits, char deleteYn) {
this.title = title;
this.content = content;
this.writer = writer;
this.hits = hits;
this.deleteYn = deleteYn;
}
}
@Getter
getter 메소드를 생성해주는 lombok 의 기능입니다.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
기본 생성자를 생성해주는 어노테이션으로, access 옵션을 추가하여 접근 범위를 설정할 수 있다.
동일 패키지 내에서만 해당 클래스를 접근 할 수 있도록 PROTECTED 로 설정.
@Entity
해당 클래스가 Table의 역할을 한다는 것을 명시하는 어노테이션이다.
별도로 테이블명을 옵션으로 지정할 수 있지만, board 라는 테이블을 생성할 것으로 패스.
@Id
PK 역할을 하는 컬럼을 지정 한다고 생각하면 된다.
@GeneratedValue(strategy = GenerationType.IDENTITY)
PK 생성 전략을 설정하는 어노테이션이라고 합니다.
IDENTITY 는 MySQL의 auto increment 기능을 구현해준다.
@Setter
setter 를 추가하지 않는 것은 Entity 객체는 Table 과 같으므로, 각 변수 = 컬럼의 정보에 대해 무작정 setter 가 된다고 하면 해당 컬럼의 데이터가 언제 어떻게 들어갔는 지 알 수 없다. Entity에서는 사용하지 않거나, 특정 컬럼 정보에 한해서 어노테이션을 적용해주면 되는 것 같다.
4. repository - BoardRepository 생성
package com.mkdevlab.springbootboard.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.mkdevlab.springbootboard.domain.Board;
public interface BoardRepository extends JpaRepository<Board, Long>{
}
Repository 는 interface 이고, JpaRepository 라는 인터페이스를 상속 받아 JPA 내 구현체를 사용할 수 있다.
JpaRepository 를 상속 받을 때 Generic 으로 Entity 와, PK 컬럼의 데이터 타입을 넣어주면 된다.
(MyBatis 와 정말 많이 다르다!!)
5. Create, Read, Delete Test
package com.mkdevlab.springbootboard.board;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.mkdevlab.springbootboard.domain.Board;
import com.mkdevlab.springbootboard.repository.BoardRepository;
@SpringBootTest
public class BoardTests {
@Autowired
BoardRepository boardRepository;
@Test
void save() {
// 게시글 파라미터 생성
Board param = Board.builder()
.title("3번 게시글 제목")
.content("3번 게시글입니다.")
.writer("mkdevlab")
.hits(0)
.deleteYn('N')
.build();
// 게시글 저장
boardRepository.save(param);
Board entity = boardRepository.findById((long) 3).get();
assertThat(entity.getTitle()).isEqualTo("1번 게시글 제목");
assertThat(entity.getContent()).isEqualTo("1번 게시글입니다.");
assertThat(entity.getWriter()).isEqualTo("mkdevlab");
}
@Test
void findAll() {
long boardsCnt = boardRepository.count();
List<Board> boards = boardRepository.findAll();
}
@Test
void delete() {
//게시글 조회
Board entity = boardRepository.findById((long)3).get();
//게시글 삭제
boardRepository.delete(entity);
}
}
jUnit Test 는 호출 할 메소드를 더블클릭하고, 마우스 오른쪽 클릭 -> Run As -> jUnit Test 클릭으로 실행 가능하다.
save()
소스코드를 붙여넣기 전 2번 정보 테스를 했다. PK 값이 2로 상승을 했기 때문에 findById 할 때 3을 기입하였다.
앞서 생성한 BoardRepository 의 save() 메소드를 사용하여 데이터를 저장할 수 있다.
Lombok 의 Builder 로 값들을 셋팅해주고 save() 메소드를 호출 해본다.
jUnit 테스트 결과에 assertThat 으로 인해 Failure 가 발생하는 것으로 보기 위해 일부러 다른 값을 넣어보았다.
그 결과...
Table 에 값이 잘 들어갔다!!
Failure 로 떨어진게 보이고, 아래 뭐가 다른지 표시되었다.
findAll()
Count 를 조회한 것과 board 테이블을 조건 없이 전체 조회 한 것으로 볼 수 있다.
delete()
잘 삭제 됐다.
끝.
Reference:
https://congsong.tistory.com/51?category=749196