728x90
DTO(Data Transfer Object)란?
- 데이터를 전송하기 위한 객체이다.
- 클라이언트에서 서버 쪽으로 요청하는 요청 데이터와 서버에서 클라이언트 쪽으로 전송하는 응답 데이터 사이에서 사용된다.
- 어떠한 비즈니스 로직도 가져서는 안 되며 저장, 검색, 직렬화, 역직렬화 로직만 가져야 한다.
DTO 클래스를 활용할 때의 장점
- 요청 및 응답 데이터를 하나의 객체로 전달하거나 받음으로써 코드를 간결하게 유지할 수 있다.
- HTTP 요청 및 응답을 받는 핸들러 메서드는 말 그대로 요청 및 응답을 받는 것이 주목적이기 때문에 최대한 간결하게 작성되어야 한다.
- 데이터의 유효성(Validation) 검증을 단순화할 수 있다.
- DTO 클래스를 사용하면 유효성 검증 로직을 DTO 클래스로 빼내어 핸들러 메서드의 간결함을 유지할 수 있게 도와준다.
역직렬화와 직렬화
역직렬화(Deserialization)
- JSON 형식의 데이터를 DTO 같은 자바의 객체로 변환하는 것을 말한다.
직렬화(Serialization)
- 자바의 객체를 JSON 형식으로 변환하는 것을 말한다.
Entity 클래스
- 실제 데이터베이스 테이블과 매핑되는 핵심 클래스이다.
- 데이터베이스의 테이블에 존재하는 칼럼들을 필드로 가지는 객체이다.
- 데이터베이스의 테이블과 1:1 매핑이 되므로 테이블이 가지고 있지 않는 칼럼을 필드로 가져서는 안 된다.
- Entity 클래스는 데이터베이스의 영속성을 목적으로 사용하는 객체이기 때문에 요청, 응답 등에 사용되어서는 안 된다.
- DB로부터 조회된 Entity를 그대로 View로 넘기게 된다면 불필요한 정보가 노출되는 등 코드가 지저분해질 수 있기 때문이다.
- setter 메서드의 사용을 지양해야 한다. 변경되지 않는 인스턴스에 대해서도 setter 메서드를 사용하면 접근이 가능하기 때문에 객체의 무결성, 일관성 등 변조되지 않음을 보장할 수 없게 된다. 따리서 생성자를 이용해 초기화하여 불변 객체로 사용하는 것이 좋다.
- Builder를 사용하면 멤버 변수가 많아지더라도 어떤 값을 어떤 필드에 넣는지 코드를 통해 육안으로 확인 가능할 뿐만 아니라 필요한 값만을 넣는 것이 가능하다.
정리
- DTO 클래스를 사용하면 코드를 간결화하고 직관적으로 바꿀 수 있음과 동시에 요청 및 응답 데이터와 Entity 클래스 등이 여러 곳에서 사용되는 지저분한 상황을 막을 수 있다.
DTO 클래스와 Entity 클래스의 대표적인 매핑 방법
1. 자동 매핑
- ModelMapper
- Mapstruct
2. 수동 매핑
- 생성자 메서드
- Builder 패턴
자동 매핑(ModelMapper, Mapstruct)
반복 작업의 큰 부분을 차지하는 객체 간 매핑을 자동으로 가능하게 한다.
ModelMapper
- 간결한 코드 작성이 가능하다.(자동 매핑의 장점)
- 런타임 시에 객체를 분석하고 매핑하므로 Lombok 라이브러리와 충돌 없이 사용 가능하다.
- Reflection API를 사용하여 객체 필드의 정보를 추출하고 Map을 만들어 그 정보를 기준으로 매핑하는 방식이기 때문에 다른 방식보다 오버헤드가 많아 성능이 좋지 않다.
MapStruct
- 간결한 코드 작성이 가능하다.(자동 매핑의 장점)
- 객체 필드의 변경 사항이 다른 로직에 영향을 주지 않는다.
- 컴파일 시점에 코드를 생성하면서 타입이나 매핑이 불가능한 상태 등의 문제가 발생한 경우 컴파일 에러를 발생시킨다.
- 전혀 다른 형태의 필드 매핑을 시도하는 경우 해결은 가능하나 매핑 로직이 매우 복잡해진다.
두 기술의 간단한 차이점
- 두 기술 중 Mapstruct의 인기가 압도적으로 높다. 왜?
- Mapstruct는 코드 생성방식이며, ModelMapper는 Reflection 기반으로 동작한다.
- 코드 생성 방식은 생성된 코드를 통해 매핑 로직을 쉽게 파악할 수 있다.
- Reflection 기반의 동작은 매핑 로직을 쉽게 파악하기 힘들다.
- Mapstruct는 컴파일 시점에 애너테이션을 읽어 구현체를 만들어내기 때문에 Reflection이 발생하지 않는다.
- ModelMapper는 매핑이 일어날 때 Reflection이 발생한다.
Reflection이란?
- 클래스의 타입을 구체적으로 알지 못하더라도 그 클래스의 메서드, 타입, 변수에 접근할 수 있게 해주는 자바 API를 말한다.
ModelMapper와 비교했을 때 Mapstruct의 장점
- Mapstruct의 처리속도가 압도적으로 빠르다.
- Mapstruct는 컴파일 시 오류를 확인할 수 있다.
- Mapstruct는 디버깅이 쉽다.
- Mapstruct는 생성된 매핑 코드를 눈으로 직접 확인할 수 있다.
수동 매핑
- 객체 변환을 위한 별도의 과정을 거치지 않고 메서드 호출만으로 매핑이 되기 때문에 성능에 영향을 주지 않는다.
- 이름이 다른 필드 간 매핑도 Getter 등을 작성하여 매핑이 가능하다.
- 매핑하는 필드 타입이 다른 경우 컴파일 타임에 이를 식별할 수 있다.
- 변경 사항이 있을 시 매번 수정해줘야 한다.
- 필드가 너무 많거나 조합하는 형태의 데이터가 많다면 휴먼 에러가 발생할 가능성이 높다.(잘못된 매핑, 데이터 누락 등)
생성자 사용
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderDto {
private Long id;
private String name;
private Long quantity;
private OrderStatus orderStatus;
private LocalDateTime createAt;
private MemberDto memberDto;
}
OrderDto orderDto = new OrderDto(1, "computer",
2, OrderStatus.CHECKED, new LocalDateTime(), new MemberDto("10", "kim", "seoul")
- 코드가 간결하지만 필드가 많으면 매우 지저분해보인다.
- 어떤 자리에 어떤 값을 넣어줘야 할지 알고 있어야 한다.
- 필드가 Setter 메서드로 인해 변경될 가능성이 있다.
Builder 패턴 사용
OrderDto orderDto = OrderDto.builder()
.id(1)
.name("computer")
.quantity(2)
.orderStatus(OrderStatus.CHECKED)
.createAt(LocalDateTime.now())
.memberDto(
MemberDto.builder()
.id(10)
.name("kim")
.address("seoul")
.build())
.build()
- 필요한 데이터만 설정할 수 있다.
- 유연성을 확보할 수 있다.
- 가독성을 높일 수 있다.
- 불변성을 확보할 수 있다.
참고
https://yeoooo.github.io/java/BuilderPattern/
https://velog.io/@sally_devv/Builder-%ED%8C%A8%ED%84%B4-Dto
https://velog.io/@backtony/Spring-Mapper-Mapstruct-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
https://dev-splin.github.io/spring/Spring-ModelMapper,MapStruct/#modelmapper--mapstruct
https://wildeveloperetrain.tistory.com/101
728x90
'[JAVA] > JAVA 기본' 카테고리의 다른 글
try - catch 문을 여러 경우의 수로 한 번에 이해해보자. (0) | 2023.05.24 |
---|---|
JAVA + Spring Data JPA 프로젝트에 다중 DB를 연결해보자. (0) | 2023.05.23 |
JVM과 자바 메모리 구조 간단 요약 정리 (0) | 2023.05.05 |
자바에서의 문자열 비교 ==, equals의 차이 (0) | 2023.03.24 |
예외 던지기(throw & throws) 30초 요약 정리 (0) | 2023.03.15 |