Develope Me!

[SpringBoot] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - JPA 적용하기 본문

Java/SpringBoot

[SpringBoot] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - JPA 적용하기

코잘알지망생 2022. 2. 20. 20:14

JPA에 대해 정리를 했다면 이제 실제로 적용해보도록 하자!

 

Spring Data JPA 적용하기

 

우선 build.gradle에 Spring Data JPA와 H2 데이터베이스 의존성을 추가한다.

    implementation('org.springframework.boot:spring-boot-starter-data-jpa')
    implementation('com.h2database:h2')
더보기

1. spring-boot-starter-data-jpa

- 스프링 부트용 Spring Data JPA 추상화 라이브러리

- 스프링부트 버전에 맞춰 자동으로 JPA 관련 라이브러리 버전 관리해줌

2. h2database

- 인메모리 관계형 데이터베이스

- 별도의 설치없이 프로젝트 의존성만으로 관리 가능

- 메모리에서 실행되기에 애플리케이션을 재시작할 때마다 초기화된다는 점에서 테스트 용도로 많이 사용

 

JPA 의존성을 추가해준 뒤 도메인을 담을 domain 패키지를 생성해줬다. 

도메인은 소프트웨어에 대한 요구사항이나 문제영역이다.

예를 들어 쇼핑몰을 떠올린다면 회원, 장바구니, QnA, 주문 등을 떠올려볼 수 있겠다. 

기존엔 Mybatis를 사용해서 xml에 쿼리문을 작성하고 클래스는 쿼리의 결과만 담았었다면 이 일들을 도메인 클래스에서 해결해준다. 

 

이후 domain 패키지에 posts 패키지와 Entity 클래스인 Posts 클래스를 만들어줬다.

@Getter 
@NoArgsConstructor 
@Entity 
public class Posts {

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; //아이디

    @Column(length = 500, nullable = false) 
    private String title; //제목 (문자열 사이즈 500, Not null)

    @Column(columnDefinition = "TEXT", nullable = false)
    private String content; //내용(Text 타입, Not null)

    private String author; //글쓴이

    @Builder 
    public Posts(String title, String content, String author){
        this.title = title;
        this.content = content;
        this.author = author;
    }


}

 

더보기

[JPA 어노테이션]

1. @Entity

- JPA가 관리하는 클래스

- JPA를 사용해서 테이블과 매핑할 것이라면 @Entity를 붙여줘야 함

2. @ID

- 해당 테이블의 PK 필드

3. @GeneratedValue

- PK 생성 규칙

- strategy = GenerationType.IDENTITY 옵션을 추가하면 PK가 auto_increment될 수 있게 함

4. @Column

- 테이블의 컬럼

- 선언하지 않더라도 해당 클래스의 필드는 모두 컬럼이 됨

- 해당 클래스의 필드에선 title의 문자열 사이즈를 500으로 늘리고 content 타입을 TEXT로 변경함


[롬복 어노테이션]

5. @NoArgsConstructor

- 기본 생성자 자동 추가 ex. public Posts(){}

6. @Getter

- 클래스 내 모든 필드의 Getter 메소드를 자동 생성

7. @Builder

- 해당 클래스의 빌더 패턴 클래스 생성

- 생성자 상단에 선언하면 생성자에 포함된 필드만 빌더에 포함

 

Posts 클래스에는 'Setter' 메소드가 없다는 특이점이 있다.

자바빈 규약을 생각해서 getter/setter를 모두 생성하는 경우가 있는데 이렇게 되면 해당 클래스의 인스턴스 값들이 언제 어디서 변해야 하는 지 코드상으로 명확히 구분할 수 없어 기능 변경 시에 복잡해지는 경우가 있다.

그래서 Posts 클래스와 같은 Entity 클래스에서는 절대 Setter 메소드를 만들지 않는다. 

만약 해당 필드의 값 변경이 필요하다면 목적과 의도를 명확히 알 수 있는 메소드를 추가해야한다.

 

 

public class Order{
	public void cancelOrder(){
    	this.status = false;
    }
}

public void 주문서비스_취소이벤트(){
	order.cancelOrder();
}

 

그렇다면 Setter가 없는데 어떻게 값을 채워 DB에 삽입할까?

 

기본적인 구조는

1. 생성자를 통해 최종 값을 채우고

2. DB에 삽입하는 것이며

 

값 변경이 필요한 경우엔

1. 해당 이벤트에 맞는 public 메소드를 호출해서 변경하는 것을 전제로 한다.

 

여기선 생성자 대신 @Builder에서 제공하는 빌더 클래스를 사용해서 생성 시점에 값을 채워주려고 한다.

 

 

//생성자
//new Example(b,a)처럼 a,b 위치 변경해도 코드 실행 전까지 문제 찾을 수 없음
public Example(String a, String b){
	this.a = a;
    this.b = b;
}

//빌더
//어느 필드에 어떤 값 채울지 인지 가능
Example.builder()
	.a(a)
        .b(b)
        .build();

생성자나 빌더나 생성 시점에 값을 채운다는 점은 동일하다.

하지만 생성자의 경우엔 지금 채워야 할 필드가 무엇인지 명확히 지정할 수가 없다면

빌더의 경우엔  어느 필드에 어떤 값을 채워야 할 지 명확하게 인지할 수 있다. 

 

이렇게 Posts 클래스를 생성한 뒤 해당 클래스를 DB에 접근하게 할 인터페이스로 JPARepository를 생성했다.

package com.study.duple.springboot.domain.posts;

import org.springframework.data.jpa.repository.JpaRepository;

public interface PostsRepository extends JpaRepository<Posts, Long> { 

}

Mybatis에선 DAO를 통해 DB에 접근했다면

 

JPA에선

1. 인터페이스를 생성하고 

2. JpaRepository<Entity 클래스, PK타입>을 상속하면

기본적인 CRUD 메소드가 자동으로 생성된다.

 

여기에 별도로 @Repository 어노테이션을 추가할 필요는 없고 Entity 클래스와 해당 Entity Repository를 함께 위치시켜주어야 한다.

Entity 클래스는 기본 Repository없인 제대로 역할을 할 수가 없다.

 

 

다음 포스팅은 해당 클래스의 테스트 코드를 작성해볼 것이다.

(Junit 테스트도 하고 API도 작성했지만 마우스 건전지가 나간 관계로...내일 포스팅을 해야겠다ㅜㅜ)

 

Comments