[Section3] Spring MVC - 서비스 계층

2023. 6. 13. 14:39

🧑🏻‍💻 TIL(Today I Learned)


✔️ 서비스 계층, 매퍼(Mapper)

 

💡DI를 통한 서비스 계층과 API 계층 연동하기 

➡️ 서비스 계층과 API 계층이 연동한다는 의미는 API 계층에서 구현한 Controller 클래스가 서비스 계층의 Service클래스와 메서드 호출을 통해 상호작용한다는 것을 의미함

 

🔎 Service? 

➡️ 애플리케이션에 있어 Service의 의미는 도메인 업무 영역을 구현하는 비즈니스 로직과 관련 있음 

➡️서비스 계층은 비즈니스 로직을 처리하기 위해 대부분 도메인 모델을 가지고 있고 그 모델은 빈약한 도메인 모델(anemic domain model)과 풍부한 도메인 모델(rich domain model)로 구분할 수 있음 또한 DDD(도메인 주도 설계, Domain Driven Design)과 관련이 깊음 

 

 

🔎 연동 실습

MemberService

  • Controller와 DTO 실습 내용을 바탕으로 Service 클래스 작성 
    • MemberController의 핸들러 메서드와 1 : 1로 매치가 되는 것을 알 수 있음 
    • 메서드 파라미터와 리턴값으로 Member 타입 사용
Member 클래스의 역할?
: DTO가 API 계층에서 클라이언트의 RequestBody를 전달받고 클라이언트에게 되돌려 줄 응답 데이터를 담는 역할을 한다면 Member 클래스는 API 계층에서 전달받은 요청 데이터를 기반으로 서비스 계층에서 비즈니스 로직을 처리하기 위해 데이터를 전달받고 비즈니스 로직을 처리한 후에 결과 값을 다시 API 계층으로 리턴해주는 역할을 함 
→  Member 클래스와 같이 서비스 계층에서 데이터 액세스 계층과 연동하면서 비즈니스 로직을 처리하기 위해 필요한 데이터를 담는 역할을 하는 클래스를 도메인 엔티티(Entity) 클래스라고 부름

 

Member 클래스

  • Member 클래스 안에 API 계층에서 사용했던 DTO 클래스에서 사용한 멤버 변수들이 모두 포함되어 있음 
  • @Getter, @Setter
    : lombok 라이브러리에서 제공하는 애너테이션, 각 멤버 변수에 해당하는 getter/setter 메서드를 일일이 작성하는 수고를 덜어주는 편리한 유틸리티성 라이브러리 
  • @AllArgsConstructor
    : 현재 클래스에 추가된 모든 멤버 변수를 파라미터로 갖는 생성자 자동으로 생성해줌 
  • @NoArgsConstructor
    : 파라미터가 없는 기본 생성자 자동으로 생성 

Service 클래스 수정

  • Stub 데이터? 
    : 테스트나 개발 과정에서 실제 데이터를 대체하여 사용하는 가짜 데이터 

Controller 일부

  • Controller 클래스에 @RestController 애너테이션을 추가하면 Spring Bean으로 등록됨
  • Service 클래스에 @Service 애너테이션을 추가하면 Spring Bean으로 등록됨
  • 생성자 방식의 DI는 생성자가 하나일 경우에는 @Autowired 애너테이션을 추가하지 않아도 DI가 적용됨

➡️ 하지만 위 방식의 문제점에는 두 가지가 있음 

  • Controller의 핸들러 메서드가 DTO 클래스를 엔티티 클래스로 변환하는 작업까지 도맡아서 하고 있음
  • 엔티티 클래스의 객체를 클라이언트의 응답으로 전송함으로써 계층 간의 역할 분리가 이루어지지 않음 

➡️ 그래서  DTO 클래스와 엔티티 클래스를 서로 변환해 주는 매퍼(Mapper) 필요

 

 

🔎 MapStruct

➡️ DTO 클래스처럼 Java Bean 규약을 지키는 객체들 간의 변환 기능을 제공하는 매퍼 구현 클래스를 자동으로 생성해 주는 코드 자동 생성기

➡️ 매퍼 클래스를 직접 만들 수도 있지만 도메인 업무 기능이 늘어날 때마다 개발자가 일일이 만들어주는 것은 비효율적인 일, 그래서 이 MapStruct가 매퍼클래스를 자동으로 구현해 줌으로써 생산성이 향상될 수 있음 

  • build.gradle에 의존성 라이브러리 추가 

  • MapStruct 기반의 매퍼(Mapper) 인터페이스 만들기
  • MemberMapper 인터페이스의 구현 클래스는 Gradle의 build task를 실행하면 자동으로 생성됨 
더보기

🔻 MemberMapper 인터페이스의 구현 클래스의 생성

 

  • 왼쪽 상단 Gradle 클릭하고 [프로젝트명 - Tasks - build - build 더블 클릭] 이렇게 하면 구현 클래스가 생성됨 
  • build 디렉토리에서 생성된 구현 클래스 확인 가능함!

 

✔️ DTO 클래스와 엔티티 클래스를 매핑해서 변환하는 이유 (역할 분리의 이유)

  1. 계층별 관심사의 분리
    ➡️ 서로 사용되는 계층이 다름, 즉 기능에 대한 관심사가 다름 그렇게 때문에 분리를 하는 것
    ➡️ 하나의 클래스나 메서드에서 여러 개의 기능을 구현하는 것은 객체 지향적이지 못함 

  2. 코드 구성의 단순화
    ➡️ 만약 DTO 클래스에서 사용하는 유효성 검사 애너테이션이 Entity 클래스에서 사용된다면 JPA에서 사용하는 애너테이션과 뒤섞인 상태가 되어 유지보수하기가 상당히 어려운 코드가 됨 

    3. REST API 스펙의 독립성 확보 
    ➡️ 데이터 액세스 계층에서 전달받은 데이터로 채워진 Entity 클래스를 클라이언트의 응답으로 전달하게 되면 원치 않는 데이터까지 클라이언트에게 전송될 수 있음 
    ➡️ 위의 경우  DTO 클래스를 사용하면 회원의 로그인 패스워드 같은 정보를 클라이언트에게 노출하지 않고 원하는 정보만 제공할 수 있음 

 

BELATED ARTICLES

more