1. JPA 소개
JPA 소개는 전에 작성한 글을 참조 해 주세요!
https://arinlee.tistory.com/36?category=930276
JPA란
JPA란 Java Persistence API의 약자로 자바 진영의 ORM 기술 표준이다. ORM(Object-Relational Mapping) Object-relational mapping(객체 관계 매핑) 객체는 객체대로 설계하고 관계형 데이터베이스는 관계형 데이..
arinlee.tistory.com
앞으로 게시판을 만들어 볼 것인데, 이 게시판의 요구사항은 다음과 같습니다.
게시판 기능 - 게시글 조회, 등록, 수정, 삭제
회원 기능 - 구글/네이버 로그인, 로그인한 사용자 글 작성 권한, 본인 작성 글에 대한 권한 관리
2. 프로젝트에 Spring Data JPA 적용하기
1. build.gradle
먼저 build.gradle에 jpa와 h2database 의존성을 등록합니다.
2. domain
의존성이 등록되었다면 domain을 담을 패키지를 만들어 줍니다.
도메인이란 게시들, 댓글, 회원 등 소프트웨어에 대한 요구사항 혹은 문제 영역이라고 생각하시면 됩니다. 행위와 데이터를 아우르는 개념이라고 생각하면 이해하기 쉽습니다.
저는 작년에 동기와 프로젝트를 같이 진행하면서 프로젝트 구조를 짤 때 domain과 dao을 살짝 혼동했었는데요,
MyBatis와 같은 쿼리 매퍼를 사용했다면 dao를 사용하면 되는데 저희는 JPA를 사용하니까 xml에 쿼리를 담고 클래스는 쿼리의 결과만 담던 일들이 이제는 모두 도메인에서 일어나게 됩니다.
3. posts
domain 패키지에 posts 패키지와 Posts 클래스를 만듭니다.
package com.example.springbootwebservice.domain.posts;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter //클래스 내 모든 필드의 Getter 메소드를 자동 생성
@NoArgsConstructor //기본 생성자 자동 추가(lombok)
@Entity //테이블과 링크될 클래스임을 나타낸다.
public class Posts {
@Id //해당 테이블의 PK필드를 나타낸다.
@GeneratedValue(strategy = GenerationType.IDENTITY) //PK의 생성 규칙을 나타낸다.
private Long id;
@Column(length = 500, nullable = false)
private String title;
@Column(columnDefinition = "TEXT",nullable = false)
private String content;
private String author;
@Builder //해당 클래스의 빌더 패턴 클래스를 생성
public Posts(String title, String content, String author){
this.title=title;
this.content=content;
this.author=author;
}
}
Posts 클래스는 실제 DB의 테이블과 매칭될 클래스입니다.
이 클래스에는 Setter 메소드가 없습니다.
getter/setter를 무작정 생성하면 생기는 문제
-> 해당 클래스의 인스턴스 값들이 언제 어디서 변해야 하는지 코드 상으로 명확하게 구분할 수가 없다. (추후 기능 변경 시 복잡해짐)
따라서 Entity 클래스에서는 절대 setter 메소드를 만들지 않는다. (대신 값 변경이 필요하면 그 목적/의도를 나타내는 메서드를 만들어 해결)
setter가 없는 상황에서 어떻게 값을 받아 DB에 삽입하는지?
기본적인 구조는 생성자를 통해 값을 채운 후 DB에 삽입하는 것이며, 값 변경이 필요한 경우 해당 이벤트에 맞는 메소드를 호출하여 변경하는 것을 전제로 한다.
여기에서는 생성자 대신 @Builder를 통해 제공되는 빌더 클래스를 사용한다. (생성자나 빌더나 생성 시점에서 값을 채워주는 역할은 똑같다.) -> 생성자의 경우 지금 채워야 할 필드가 무엇인지 명확히 지정할 수 없다. 빌더를 사용하게 되면 어느 필드에 어떤 값을 채워야 할 지 명확하게 인지 가능
4. JpaRepository
package com.example.springbootwebservice.domain.posts;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostsRepository extends JpaRepository<Posts, Long> {
}
보통 Mybatis 등에서 Dao라고 불리는 DB Layer 접근자이다.
인터페이스 생성 후, JpaRepository<Entity 클래스, PK 타입>를 상속하면 기본적인 CRUD 메소드가 자동으로 생성된다.
이 책에서는 Entity 클래스와 기본 Entity Repository는 함께 위치해야 한다고 한다. 둘은 아주 밀접한 관계이고, Entity 클래스는 기본 Repository 없이는 제대로 역할을 할 수가 없기 때문이다.
작년에 진행한 프로젝트에서는 Domain과 Repository 패키지를 따로 나눴는데 프로젝트 규모가 커져 도메인 별로 프로젝트를 분리해야 하는 경우 위 설명대로 하는 것이 좋을 것 같다.
3. 테스트 코드 작성
package com.example.springbootwebservice.domain.posts;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest
public class PostsRepositoryTest {
@Autowired
PostsRepository postsRepository;
@After //JUnit에서 단위 테스트가 끝날 떄마다 수행되는 메소드를 지정
public void cleanup(){
postsRepository.deleteAll();
}
@Test
public void 게시글저장_불러오기(){
//given
String title = "테스트 게시글";
String content = "테스트 본문";
postsRepository.save(Posts.builder() //테이블 posts에 insert/update 쿼리를 실행
.title(title)
.content(content)
.author("arin")
.build());
//when
List<Posts> postsList = postsRepository.findAll(); //posts에 있는 모든 데이터를 조회
//then
Posts posts = postsList.get(0);
assertThat(posts.getTitle()).isEqualTo(title);
assertThat(posts.getContent()).isEqualTo(content);
}
}
별다른 설정 없이 @SpringBootTest를 사용하면 H2 데이터베이스를 자동으로 실행해 준다.
실행된 쿼리를 로그로 보고 싶다면 application.properties 파일에서 설정해주면 됩니다.
MySQL 문법을 따르도록 설정했고 결과는 다음과 같습니다.
'개발 > Spring' 카테고리의 다른 글
CRUD API (0) | 2022.07.07 |
---|---|
[Spring Boot] 도메인 계층에서 비즈니스 로직 처리 (0) | 2022.07.05 |
[SpringBoot] 테스트 코드 작성, TDD (0) | 2022.05.17 |
[SpringBoot] 인텔리제이로 스프링 부트 시작하기 (0) | 2022.05.16 |
Spring Boot Validation (0) | 2022.02.05 |