1. 시작하게 된 계기 및 다짐 😮
  • 이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.

    • 그 날 배웠던 것을 길지 않아도 좋으니 정리하며 복습하는 습관 기르기
    • 주말에 다음주에 배울 내용들을 예습
    • 코딩 문제와 java코드들은 꾸준히 학습
    • 자료구조를 이용한 알고리즘 문제 해결 학습
  1. 학습 목표 😮
목표결과
DI(Dependency Injection)를 사용해서 API 계층과 서비스 계층을 연동O
API 계층의 DTO 클래스와 서비스 계층의 엔티티(Entity) 클래스를 매핑O
  1. 정리

DI를 통한 서비스 계층과 API계층 간 연동

# Controller 와 Service 클래스의 메서드를 통한 상호작용

0. @애너테이션
 1). @Getter/@Setter
   - lombok 라이브러리의 편리성 메서드
 2). @AllArgsConstructor
   - 해당 클래스의 모든 파라미터를 포함한 생성자를 자동으로 생성
 3). @NoArgsConstructor
   - 파라미터가 없는 기본 생성자를 자동으로 생성

1. Service 의미
 - Service는 도메인 업무 영역을 구현하는 비지니스 로직
 - 대부분의 서비스 계층의 업무는 도메인 모델을 포함 
 - ★도메인 모델은 DDD(도메인 주도 설계, Domain Driven Design)와 관련이 깊다.
    => DDD는 심화적인 영역이라, 추후 JDBC학습시 추가적 학습
 
 1). 빈약한 도메인 모델(anemic domain model)
 2). 풍부한 도메인 모델(rich domain model)


2. 비지니스 로직 처리 Service 클래스 
 - API계층에서 받은 데이터를 기반으로 서비스 계층에서 비지니스 로직을 처리하고 이를 다시 API 계층으로 보내는 역할
 - 도메인 엔티티 클래스 : 서비스 계층 <-> 데이터 계층을 연동하며 비지니스 처리하기 위한 데이터를 담은 클래스


3. DI(Dependency Injection)없이 비지니스 계층과 API계층 연동
 - new 생성자 키워드를 통한 객체생성 및 클래스 메서드 호출
 - 강한 결합상태

4. DI를 적용한 비지니스 계층과 API 계층 연동
 - 느슨한 결합
 - 생성자 주입과 Bean으로 사용하기 위한 @Service
 - 생성자 1개 이상은 @Autowired

5. 문제점 
 1). MemberController의 핸들러 메서드가 DTO 클래스를 엔티티(Entity) 클래스로 변환하는 작업까지 도맡아서 하고 있다.
      [Ex. Controller 클래스에서 DTO객체를 엔티티 객체로 변환하는 작업까지 하고있음]
 2). 엔티티(Entity) 클래스의 객체를 클라이언트의 응답으로 전송함으로써 계층 간의 역할 분리가 이루어지지 않았다.
      [Ex. Member 클래스를 응답으로 전송]

[Extra]
1). DDD(Domain Driven Design)
 - https://ko.wikipedia.org/wiki/도메인주도설계
 - https://ko.wikipedia.org/wiki/빈약한도메인모델
 - https://martinfowler.com/eaaCatalog/domainModel.html
 - https://martinfowler.com/tags/domain driven design.html

2). lombok
 - https://projectlombok.org/features/all
 [ex. @Getter/Setter, @NoArgsConstructor, @AllArgsConstructor, @ToString, @Data)






매퍼(Mapper)를 이용한 DTO 클래스와 엔티티(Entity) 클래스 간 매핑


0. @애너테이션
 1). @Mapper(componentModel = "spring");
   - MapStruct 매퍼 인터페이스로 정의

1. Mapper 클래스 구현
 - 기존의 두가지 문제를 Mapper 클래스를 통하여 해결(엔티티객체 -> DTO 객체 변환 응답, DTO객체 -> 엔티티 객체 변환)
 - Mapper 클래스와 MemberService 클래스를 이용하여
   각, DTO객체 <-> 엔티티 클래스 객체를 변환


2. MapStruct 클래스(인터페이스 기반)
 - ★매퍼(Mapper) 구현 클래스를 자동으로 생성해주는 코드 자동 생성기
 - 특정 서비스 클래스에 한하지 않고, MapStruct가 매퍼 서비스 클래스의 매퍼 클래스를 자동으로 구현
 - 일일이, 각 매퍼 클래스를 구현해줄 필요가 없음

[dependencides {
	implementation 'org.mapstruct:mapstruct:1.4.2.Final'
	annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}]

3. MapStruct 기반의 매퍼(Mapper) 인터페이스 정의
 - ★많은 Mapping라이브러리들이 존재하는데 그중, [Mapstruct > ModelMapper]가 자주 사용됨
  1). ModelMapper : Runtime시 Java 리플렉션 API를 이용해 매핑진행
  2). MapStruct : 컴파일 타임에 이미 Mapper가 모두 생성되어 있음
 - MapStruct가 @Mapper(...)인터페이스를 기반으로 매퍼(Mapper)구현 클래스를 자동으로 생성해준다.
 - [Gradle] 탭을 클릭한 후, [프로젝트 명 > Tasks 디렉토리 > build 디렉토리 > build task]를 더블 클릭하면     MapStruct로 정의된 인터페이스의 구현 클래스가 생성
    [자동으로 생성 되긴함]
 - [Project 탭 > 프로젝트명 > build] 디렉토리내의 MemberMapper 인터페이스가 위치한 패키지 안에 생성
 
 [예제 Code]================================================================
 import com.codestates.member.dto.MemberPatchDto;
 import com.codestates.member.dto.MemberPostDto;
 import com.codestates.member.dto.MemberResponseDto;
 import com.codestates.member.entity.Member;
 import org.mapstruct.Mapper;

 @Mapper(componentModel = "spring")  // (1)
 public interface MemberMapper {
     Member memberPostDtoToMember(MemberPostDto memberPostDto);
     Member memberPatchDtoToMember(MemberPatchDto memberPatchDto);
     MemberResponseDto memberToMemberResponseDto(Member member);
 }
 =======================================================================



4. DTO 클래스와 엔티티 클래스의 역할 분리가 필요한 이유
 - DTO클래스와 엔티티(Entity) 클래스를 매핑해서 변환하는 이유
 1). 계층별 관심사의 분리
    (1) DTO : API 계층에서 요청 데이터를 전달받고 응답하는 목적
    (2) Entity : 서비스 계층에서 데이터 엑세스 계층과 연동하여 비지니스 로직 결과로 생성된 데이터를 다루는 목적

 2). 코드 구성의 단순화
    (1) 분리하지 않을시, DTO 클래스의 유효성검사 애너테이션이 Entity 클래스에서 사용되면 JPA에서 사용하는 애너테이션과 뒤섞인 상태가 되어 유지보수가 어려움
 
 3). REST API 스펙의 독립성 확보
    (1) 데이터 계층의에서 전달 받은 데이터로 채워진 Entity 클래스를 그대로 응답으로 전달하면 원치않는 데이터까지 클라이언트에 전송이 됨
    [Ex. 로그인 패스워드]



[Extra]
1). MapStruct 
 - https://mapstruct.org/
 - https://mapstruct.org/documentation/installation/
 - https://mapstruct.org/documentation/stable/reference/pdf/mapstruct-reference-guide.pdf
 - https://github.com/mapstruct/mapstruct-examples






Extra

0). Domain/Entity/Vo 객체 차이
 - Domain : 개발하고자 하는 영역을 분석한 결과로 도출된 객체들 (ex. purchase, purchase_detail, Member, Product)
 - Entity : 식별자를 가지고있는 객체, DB와 비슷(ex. Member, product)
 - Vo : 식별자없이 그저 값만 들어있는 객체

실습 정리

0. Coffee 클래스의 서비스계층과 API계층의 연동 실습

1. CoffeeService 클래스 구현
 1). @Service를 이용하여 빈 컨테이너에 빈으로 등록 (@Service 영역)
 2). 기존 MemberService 클래스를 참조하여 생성
 3). Dto 객체가 아닌 Entity객체를 이용하여 생성
 4). 구체적인 내용은 데이터 계층과 연동이 없어서 생략
 
2. CoffeeController 클래스 구현(수정)
 1). Client에 받은 데이터를 @Requestbody애네터이션을 이용하여 Dto객체로 받음
 2). 해당 Dto객체의 비지니스 로직을 처리하기 위한 Entity객체로 변경
 3). 처리한 Entity객체를 다시 API계층과 통한 하기 위한 Dto객체로 변경

3. CofeeMapper 클래스 구현
 1). MapStruct(인터페이스)를 이용하여 Mapper클래스를 직접 구현하지 않고 자동으로 구현하도록 만듬
 2). Dto -> Entity 객체를 위한 메서드를 생성
 3). Entity -> Dto 객체를 위한 메서드 생성
  1. 피드백 😮
  • 앞서 배운 Client의 요청을 Server로 리소스를 전달받고 응답하는 API계층과 이 리소스를 편리하게 받기위한 Dto객체로 받는 내용을 기반으로 이제 서비스계층과 연동하기 위하여 이 Dto객체를 Entity객체로 변환하는 내용을 배우고 실습하였다.

  • 굳이 Entity 객체로 변경하는 이유는, 계층 간 역할의 분리를 확실하게 해주기 위해서고, 코드의 단순화를 통하여 유효성 검사 애너테이션이 뒤섞임을 방지하고 , 필요한 데이터만을 응답하기 위해서이다.

  • Mapper의 경우 MapStruct 인터페이스를 기반으로 아주 편리하게 메서드만 정의하면 자동으로 변환해주는 클래스를 컴파일시에 만들어주어 편리하다.

  1. 앞으로 해야 될 것 😮
  • 매일 꾸준히 할 것
    • 꾸준히 velog 작성
    • Java 언어 및 Algorithm 공부(Coding-Test)
    • 틈틈히 운동 하기

  • 내일 해야 할 것
    • 예외 처리를 위한 ExceptionHanlder 학습
    • 다양한 예외 처리 방법에 대한 학습
profile
Will be great Backend-developer

0개의 댓글