givepro

DTO 사용 시 참고사항 (@NoArgsConstructor, Mapper) 본문

백엔드/SpringBoot

DTO 사용 시 참고사항 (@NoArgsConstructor, Mapper)

givepro 2022. 10. 27. 14:22
반응형

DTO란?

Data Transfer Object의 약자로, 계층 간 데이터 전송을 위해 도메인 모델 대신 사용되는 객체이다.

이때, 계층이란 Presentation(View, Controller), Business(Service), Persistence(DAO, Repository) 등을 의미한다.

 

DTO는 순수하게 데이터를 저장하고, 데이터에 대한 getter, setter 만을 가져야한다고 한다. 위키피디아에 따르면 DTO는 어떠한 비즈니스 로직을 가져서는 안되며, 저장, 검색, 직렬화, 역직렬화 로직만을 가져야 한다고 한다.

직렬화는 DTO를 Byte, Json, Xml 등의 형태로 변환하는 것을 의미한다. 역직렬화는 그 반대를 의미한다.

도메인 대신 DTO를 사용하도록 한다. (외부 노출 방지, 도메인 모델 캡슐화 → 보호)

 

POST 요청 시 @RequestBody 오류 해결

보통 일반적인 GET 요청 시의 메소드에서는 @Data 어노테이션으로 선언된 DTO 클래스로 해결이 가능했다.

하지만 POST 요청 시 @Data 어노테이션만으로는 해결이 안된다는 것을 개발하면 알게 되었다. 보통 아래와 같이 에러가 발생한다.

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of "DtoClassName"
(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
serialize(직렬화) - 객체의 상태를 바이트 스트림으로 변환하는 작업
deserialize(역직렬화) - 바이트 스트림을 다시 객체형태로 변환하는 작업

기본 생성자가 없어서 역직렬화의 실패라고 나온다.

 

그럼 해결하기 위해서는 DTO 클래스에 아래의 어노테이션을 추가하도록 하자.

@AllArgsConstructor - 모든 필드 값을 파라미터로 받는 생성자를 만들어준다.
@NoArgsConstructor - 파라미터가 없는 기본 생성자를 생성해준다. 

 

지금 문제의 경우 기본 생성자가 없기 때문에 발생하는 것으로 @NoArgsConstructor를 추가해주면 해결이 된다.

하지만 경험상 DTO 클래스 작성시 두 개의 어노테이션을 모두 같이 작성해주는게 작업을 하는데 있어서 좋은 듯하다.

 

ModelMapper 사용 하기

우선 Mapper를 사용하게된 계기는 아래와 같다.

새로운 파라미터가 발생할때마다 DTO 클래스에 엔티티 변환 로직을 추가해야 하는 점

 

하지만 Mapper를 사용하면 전달된 파라미터의 리스트와 엔티티를 비교하여 자동으로 변환해준다.

나의 경우 ModelMapper를 Bean으로 등록하여 사용하였다.

@Configuration
public class ModelMapperConfig {
    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }
}
@Service
@RequiredArgsConstructor
public class SampleService {

    private final ModelMapper modelMapper;
    
    @Override
    public void updateSample(SampleDto param) {
        Sample sample = modelMapper.map(param, Sample.class);
        // 중간 생략 ...
    }
    
}
Comments