엔티티(Entity), 매퍼(Mapper), MapStruct

귀찮Lee·2022년 6월 28일
1

Spring

목록 보기
19/30

◎ 엔티티(Entity)

  • 엔티티(Entity)

    • 데이터베이스에 쓰일 필드와 여러 엔티티간 연관관계를 나타내는 객체 (실제 DB의 테이블과 매칭될 클래스)
    • DB에 사용될 기본 구조를 나타낼 객체
  • DTO와 구분하여 사용하는 이유 (Entity의 필요성)

    • 계층별 관심사 분리

      • DTO는 요청 데이터를 받고, 응답 데이터를 전송하는 것이 목적
      • Entity는 데이터 엑세스 계층과 연동하여 비즈니스 로직의 결과로 생성된 데이터를 다루는 것이 목적
      • Single Responsibility Principle / 하나의 클래스나 메서드가 여러 기능을 하는 것은 리팩토링 대상
    • 코드 구성의 단순화

      • 만약 한 객체로 모든 일을 처리한다면, 한 클래스 내에서 유효성 검사 코드, 데이터 엑세스 접근 코드 ... 이 들어가 상당히 유지보수하기 어려워짐
    • REST API 스펙의 독립성 확보

      • 한 객체만 사용한다면, http 응답을 보낼 때, 원치 않는 데이터까지 보내진다.
      • Entity와 DTO를 나눈다면 특정 데이터만 보내기 용이해짐

◎ 매퍼(Mapper)

  • 매퍼의 필요성

    • DTO와 Entity의 역할이 서로 다르지만, 똑같이 데이터를 옮기고 있으므로 두 객체를 서로 변환해주어야 할 필요가 있다.
    • DTO(요청 받는 객체) -> Entity(비즈니스 로직, 데이터 엑세스) -> DTO(응답 보내는 객체)
  • Mapper 클래스 직접 구현

    • mapper는 Controller에서 DI를 통해 사용하며, Service에게는 대체적으로 Entity를 넘김
    • 예시
      @Component  // (1)
      public class MemberMapper {
              // (2) MemberPostDto를 Member로 변환
          public Member memberPostDtoToMember(MemberPostDto memberPostDto) {
              return new Member(0L,
                      memberPostDto.getEmail(), 
                      memberPostDto.getName(), 
                      memberPostDto.getPhone());
          }
      }
  • mapping framework

    • MapStruct, ModelMapper ... 가 있음
    • ModelMapper : Runtime시 Java의 리플렉션 API를 이용해서 매핑을 진행
    • MapStruct : 파일 build시에 전부 만들어 놓음
      • MapStruct가 성능적으로 뛰어남

◎ MapStruct

  • MapStruct (mapping framework)의 필요성

    • Mapper는 하는 일과 코드가 유사함 -> 일일이 수작업으로 매퍼(Mapper) 클래스를 만드는 것은 비효율적
    • Mapper는 DTO와 Entity의 수와 유사한 개수만큼 만들어 주어야 한다.
    • 특정 라이브러리를 통해 자동으로 구현하는 것이 매우 용이
  • MapStruct

    • Java Bean 규약을 지키는 객체들 간의 변환 기능을 제공하는 매퍼(Mapper) 구현 클래스를 자동으로 생성해주는 코드 자동 생성기
  • MapStruct 프레임워크 추가

    // Lombok과의 순서가 중요
    dependencies {
        implementation 'org.projectlombok:lombok:1.18.24'
        implementation 'org.mapstruct:mapstruct:1.5.1.Final'
        annotationProcessor "org.projectlombok:lombok:1.18.24"
        annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.1.Final'
    }
  • MapStruct 정상적으로 매핑하기 위한 조건

    • 우선 순위가 높은 순으로 구현함
    1. Builder 패턴이 적용되어 있는 경우
    2. @AllArgsConstructor 가 있는 경우 (모든 필드의 파라미터를 가지는 생성자)
      • 기본 생성자가 포함되어 있는 경우, 2번이 제역할을 하지 못함
    3. setter 메서드가 있는 경우
  • MapStruct 기반의 매퍼(Mapper) 만들기

    @Mapper(componentModel = "spring")
    public interface Mapper {
        Member memberPostDtoToMember(MemberPostDto memberPostDto);
        Member memberPatchDtoToMember(MemberPatchDto memberPatchDto);
        MemberResponseDto memberToMemberResponseDto(Member member);
        // [변경 될 객체] [메서드]([변경 할 객체]) 
    }
    • @Mapper

      • 해당 인터페이스를 MapStruct의 매퍼 인터페이스로 정의
      • componentModel = "spring" : Spring의 Bean으로 등록됨
    • 실제로 구현된 객체는 Gradle의 build task를 실행하면 자동으로 생성

      • 한번 빌드하고 난 다음에 Interface에 메서드를 Ctrl + Click 하면 구현된 객체를 볼 수 있음
      • MapperImpl 생성 시기 : [프로젝트 명 > Tasks 디렉토리 > build 디렉토리 > build task]를 더블 클릭
      • MapperImpl 생성 위치 : [Project 탭 > 프로젝트명 > build] 디렉토리내의 MemberMapper 인터페이스가 위치한 패키지 안에 생성

◎ MapStruct 추가 자료

profile
배운 것은 기록하자! / 오류 지적은 언제나 환영!

0개의 댓글