애플리케이션 개발에서 DTO(Data Transfer Object)와 Entity 간의 변환은 매우 중요한 역할을 한다.
DTO는 클라이언트와 서버 간 데이터 전송을 담당하며, Entity는 데이터베이스와의 상호작용을 담당한다.
이 두 계층 사이의 변환을 깔끔하고 일관성 있게 처리하기 위해 TypeChange라는 헬퍼 클래스를 활용해보려고 한다.
쉽게 이해하기 위해 회원가입 로직을 바탕으로 설명을 해보겠다.
package com.swyp.playground.domain.parent.service;
@Service
@RequiredArgsConstructor
public class ParentService {
private final ParentRepository parentRepository;
private final TypeChange typeChange;
private final PasswordEncoder passwordEncoder;
public ParentCreateResDto signUp(ParentCreateReqDto request) {
String encodedPassword = passwordEncoder.encode(request.getPassword());
Parent parent = typeChange.parentCreateReqDtoToParent(request, encodedPassword);
Parent savedParent = parentRepository.save(parent);
return typeChange.parentToParentCreateResDto(savedParent);
}
}
엇... 뭔가 상당히 간단하지 않은가??
깔끔그자체

TypeChange 클래스란?
TypeChange는 DTO를 Entity로, 또는 Entity를 DTO로 변환하는 작업을 담당하는 컴포넌트 클래스이다.
이 클래스를 사용하면 DTO와 Entity 간의 변환 로직을 재사용 가능하게 만들고, 컨트롤러나 서비스 코드에서 변환 작업을 분리하여 가독성과 유지보수성을 높일 수 있다.
아래 코드를 보면서 살펴보자.
package com.swyp.playground.common.domain;
import com.swyp.playground.domain.parent.domain.Parent;
import com.swyp.playground.domain.parent.dto.req.ParentCreateReqDto;
import com.swyp.playground.domain.parent.dto.res.ParentCreateResDto;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Component
public class TypeChange {
public Parent parentCreateReqDtoToParent(ParentCreateReqDto dto, String encodedPassword) {
return Parent.builder()
.name(dto.getName())
.email(dto.getEmail())
.password(encodedPassword)
.nickname(dto.getNickname())
.address(dto.getAddress())
.role(dto.getRole())
.birthDate(dto.getBirthDate())
.phoneNumber(dto.getPhoneNumber())
.childCount(dto.getChildCount())
.introduce(dto.getIntroduce())
.joinedAt(LocalDateTime.now())
.mannerTemp(BigDecimal.valueOf(50.0))
.build();
}
// Parent 엔티티를 ParentCreateResDto로 변환
public ParentCreateResDto parentToParentCreateResDto(Parent parent) {
return ParentCreateResDto.builder()
.id(parent.getParentId())
.name(parent.getName())
.email(parent.getEmail())
.nickname(parent.getNickname())
.build();
}
}
1. ParentCreateReqDto → Parent (DTO → Entity)
클라이언트로부터 전달받은 ParentCreateReqDto 객체를 데이터베이스에 저장 가능한 Parent 엔티티로 변환하는 작업
- Builder 패턴: Builder를 활용해 가독성을 높이고, 필드 초기화를 안전하게 처리.
2. Parent → ParentCreateResDto (Entity → DTO)
데이터베이스에서 조회한 Parent 엔티티를 클라이언트로 반환하기 위한 ParentCreateResDto로 변환한다.
TypeChange 클래스를 활용하는 이유
- 코드 재사용성 증가
변환 로직을 하나의 클래스로 관리함으로써, 다양한 서비스 계층에서 동일한 로직을 중복 구현하지 않아도 됨 - 가독성과 유지보수성 향상
변환 로직이 분리되어 있어, 컨트롤러와 서비스 계층의 코드를 간결하고 읽기 쉽게 만들어줌 - 일관성 유지
DTO와 Entity 간 변환 규칙을 중앙 집중적으로 관리하여, 변환 작업에 일관성을 제공한다. - 테스트 용이성
변환 로직을 독립적으로 테스트할 수 있으므로, 예외 처리나 예상치 못한 입력 데이터에 대한 검증이 간편하다.
만약 typechange의 방법을 사용하지 않았다면, service의 코드는 아래와 같이 적을 수 있겠다.
@Service
public class ParentService {
private final ParentRepository parentRepository;
private final PasswordEncoder passwordEncoder;
public ParentService(ParentRepository parentRepository, PasswordEncoder passwordEncoder) {
this.parentRepository = parentRepository;
this.passwordEncoder = passwordEncoder;
}
public ParentCreateResDto signUp(ParentCreateReqDto request) {
String encodedPassword = passwordEncoder.encode(request.getPassword());
Parent parent = Parent.builder()
.name(request.getName())
.email(request.getEmail())
.password(encodedPassword)
.nickname(request.getNickname())
.address(request.getAddress())
.role(request.getRole())
.birthDate(request.getBirthDate())
.phoneNumber(request.getPhoneNumber())
.childCount(request.getChildCount())
.introduce(request.getIntroduce())
.joinedAt(LocalDateTime.now())
.mannerTemp(BigDecimal.valueOf(50.0))
.build();
Parent savedParent = parentRepository.save(parent);
return ParentCreateResDto.builder()
.id(savedParent.getParentId())
.name(savedParent.getName())
.email(savedParent.getEmail())
.nickname(savedParent.getNickname())
.build();
}
}
'SpringBoot' 카테고리의 다른 글
| 분산 이벤트 스트리밍 플랫폼, Kafka 아는척해보기 (3) | 2025.08.17 |
|---|---|
| Swagger를 사용해서 쉽게 api명세서를 만들어보자! (2) | 2024.12.01 |
| Springboot에서 SMTP(google)를 통해 인증번호를 보내보자! (1) | 2024.11.29 |
| JWT, Redis를 활용하여 RefreshToken을 관리해보자! (0) | 2024.11.27 |
| Springboot + MySQL 연결하기 (2) | 2024.11.17 |