스프링 부트에서 JPA로 데이터베이스를 다뤄보자(3) - 등록/수정/조회 API 만들기

Wintering·2022년 6월 11일
0
post-custom-banner

API를 만들기 위해서는 총 3개의 클래스가 필요함

  • Request 데이터를 받을 Dto
  • API 요청을 받을 Controller
  • 트랜잭션, 도메인 기능 간의 순서를 보장하는 Service
    • Service에서 비지니스 로직을 처리하는 게 아님.
      Service에서는 트랜젝션, 도메인 간의 순서보장 역할만 해줌.

Spring 웹 계층

  • Web Layer
    • 컨트롤러(@Controller)와 JSP/Freemaker등의 뷰 템플릿 영역
    • 이외에도 필터(@Filter), 인터셉터, 컨트롤렁 어드바이스 등 외부 요청과 응답에 대한 전반적인 영역
  • Service Layer
    • @Service에 사용되는 서비스 영역
    • 일반적으로 Controller와 Dao의 중간 영역에서 사용
    • @Transactional이 사용되어야 하는 영역
  • Repository Layer
    • DB에 접근하는 영역
    • DAO(Database Access Obeject) 영역이라고 이해하면 됨
  • Dtos
    • Dto(Data transfer Object) 계층 간의 데이터 교환을 위한 객체들의 영역
    • 뷰 템플릿 엔진에서 사용될 객체나 Repository Layer에서 결과로 넘겨준 객체 등
  • Domain Model
    • 도메인이라고 불리는 개발 대상을 모든 사람이 동일한 관점에서 이해할 수 있고 공유할 수 있도록 단순화시킨 것
    • @Entity를 사용한 영역은 모두 도메인 모델이라고 생각하면 됨
    • 다만, 무조건 데이터베이스의 테이블과 관계가 있어야만 하는 것은 아님
    • VO처럼 값 객체들도 이 영역에 해당

이 5가지의 영역 중에서 비지니스 처리를 담당해야 하는 곳은?
Domain
(기존에 서비스로 처리하던 방식 : 트랜젝션 스크립트)

책(p.103 - 104 참고)

1. 패키지 생성하기 (폴더구조 확인하기)

PostApiController, PostsSaveRequestDto, PostService 생성

  • PostApiController

  • PostsService

cf) 스프링에서 Bean을 주입받는 방식
@Autowired < 권장X
setter
생성자 < 가장 권장하는 방식

@RequiredArgsConstructor에서 해결
: final이 선언 된 모든 필드를 인자값으로 하는 생성자를 생성해주는 어노테이션
생성자를 직접 쓰지 않고 어노테이션을 이용하면 클래스의 의존성 관계가 변경될 때마다 생성자 코드를 계속 생성해야 하는 번거로움을 없앨 수 있다.

  • PostsSaveRequestDto

    • Entity 클래스와 거의 유사한 형태임에도 Dto를 따로 생성
      Entity 클래스를 Request/Response 클래스로 사용해서는 안됨

      • Entity 클래스는 데이터베이스와 맞닿은 핵심클래스
      • 수많은 클래스가 Entity 클래스를 기준으로 동작하기 때문에 Entity클래스가 변경 될 경우 너무 많은 클래스에 영향을 미치게 된다.
      • 반면 Request와 Response Dto는 View를 위한 클래스라 매우 자주 변경이 필요
    • 꼭 Entity클래스와 Controller에서 사용할 Dto 클래스는 분리하자

PostApiControllerTest 테스트 코드 생성하기

cf) gradle version 6 이상부터는 테스트코드의 annotation이 다르게 적용되는 경우가 많으니까 잘 알아보고 적용할 것 :: 참고링크

  • 이전 HelloController와는 달리 @WebMvcTest를 사용하지 않는다
    • @WebMvcTest의 경우 JPA 기능이 작동하지 않고, Controller, ControllerAdvice등 외부와 관련된 부분만 활성화 되기 때문
    • JPA 기능까지 한꺼번에 테스트할때는 @SpringBootTest와 @TestRestTemplate를 사용

WebEnvironment.RANDOM_PORT로 랜덤포트가 실행되고 insert 쿼리가 실행 됨을 확인🔻


수정/조회 기능 생성하기

  • PostsUpdateRequestDto 생성
  • PostsResponseDto 생성
    • PostResonseDto는 Entity의 필드 중 일부만 사용
      생성자에 Entity를 받아 필드에 값을 넣어줌

  • Posts 수정

  • PostsService 수정

    • update 기능에서 쿼리를 날리는 부분이 없음
      • JPA는 영속성 컨텍스트 (엔티티를 영구 저장하는 환경)
      • JPA의 엔티티매니저가 활성화된 상태(디폴트 상태)로 트랜젝션 안에서 데이터베이스에서 데이터를 가져오면 이 데이터는 영속성 컨텍스트가 유지된 상태임
      • 이 상태에서 해당 데이터 값을 변경하면 트랜젝션이 끝나는 시점에 해당 테이블에 변경분을 반영한다. 즉, Entity 객체 값만 변경하면 별도의 update 쿼리문을 날릴 필요가X
      • Dirty Checking(더티체킹)

3. 조회/수정 testcode만들기

수정부분 테스트코드 추가

조회부분 (h2-console)

  • application.properties
spring.jpa.show_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
spring.datasource.hikari.jdbc-url=jdbc:h2:mem:testdb;MODE=MYSQL
spring.datasource.hikari.username=sa
spring.h2.console.enabled=true
  • localhost:8080/h2-console/login
  • h2 db에서 insert 문으로 데이터 넣어주기

    GET화면에서 데이터를 정상적으로 확인할 수 있음

JPA Auditing으로 생성시간/수정시간 자동화하기

domain에 BaseTimeEntity 클래스 생성

BaseTimeEntity 클래스는 모든 Entity 클래스의 상위 클래스가 되어 Entity들의 createDate, modifiedDate등을 자동으로 관리하는 역할을 수행

  • @MappedSuperclass

    • Jpa Entity 클래스들이 BaseTimeEnttiy를 상속할 경우 필드들도 칼럼으로 인식하도록 함
  • @EntityListeners(AuditingEntityListener.class)

    • BasedEntity클래스에 Auditing 기능 포함
  • @CreateDate

    • Entity가 생성되어 저장될 때 시간이 자동 저장
  • @LastModifiedDate

    • Entity가 업데이트될때 시간이 자동저장
  • Posts클래스가 BaseTimeEntity를 상속받도록 하고
    Application.class에 JPA Auditing 어노테이션이 잘 활성화 될 수 있도록
    @EnableJpaAuditing 추가

BaseTimeEntity테스트코드 작성해보기

post-custom-banner

0개의 댓글