티스토리 뷰

반응형

 

 

 

 

 

 



 

 

SpringBoot

 

 

 

api 의 요청에 의해서 정보수정이 될 때,

변경점이 없는 일부 필드들의 정보는 null 로 수신하는 경우가 있다.

(* 기존 데이터 필드를 전부 보내지 않는 경우)

 

이런 경우 Mapstruct 를 이용하여 DTO 에서 엔티티로 변환할 때,

엔티티 업데이트 시에 기존 필드가 null 로 업데이트 되는 현상을 발견 할 수 있다.

 

 

 

변경점이 없는 기존 필드들을 유지하기 위해 mapstruct 인터페이스를 수정하였다.

 

 

 

 

 

 

 


필자는 Mapstruct 인터페이스를 이용하여 DTO 와 엔티티를 치환하여 사용한다.

 

public interface GenericToMapper<DTO, Entity> {
    DTO toDTO(Entity e);
    Entity toEntity(DTO d);
}

 

 

 

 

 

 

기존 서비스에서는 요청을 받아 DTO 를 엔티티로 치환하여 인서트하거나 업데이트 해줬었다.

 

public class Service {

    private final Repository repository;
    private final ToMapper toMapper;

    public ResponseDTO save(DTO param) {
        Entity entity = toMapper.toEntity(param);  // 단순 엔티티로 치환
        repository.save(entity);
    
	...
    }
}

 

 

 

 

동작하는데 문제는 없으나,

클라이언트 요청이 일부 필드만 전달될 경우 그 외 나머지 필드들은 null 로 업데이트되는 현상을 마주하게 됐다.

 

정말 단순하게 해당 엔티티를 조회하여 전달 받은 일부 필드만 변경해줘도 되긴 하나

클라이언트로 부터 어떤 값이 전달될지 모르기 때문에 모든 필드를 null 체크를 해줘야 한다.

 

 

그래서 mapstruct 를 활용하여 아래와 같이 리펙토링 하였다.

 

 

 

 

 

 


아래와 같이 인터페이스를 수정하였다.

 

public interface GenericToMapper<DTO, Entity> {
    DTO toDTO(Entity e);
    Entity toEntity(DTO d);

    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
    void updateFromDto(DTO dto, @MappingTarget Entity.EntityBuilder builder);
}

 

 

null 값일 경우 무시하고 아닌 경우에만 치환하라는 NullValuePropertyMappingStrategy 를 사용했다.

 

필자는 모든 엔티티에 setter 가 없고 builder 를 사용하므로 위와 같이 작성하였고

setter 를 사용한다면  @MappingTarget Entity e  로 사용하면 된다.

 

 

 

 

 

구현체는 아래와 같다.

 

@Override
public void updateFromDto(DTO dto, Entity.EntityBuilder entityBuilder) {
        if ( dto == null ) {
            return;
        }

        entityBuilder.Idx( dto.getIdx() );
        if ( dto.getName() != null ) {
            entityBuilder.name( dto.getName() );
        }
        if ( dto.getUseYN() != null ) {
            entityBuilder.useYN( dto.getUseYN() );
        }
        if ( dto.getCode() != null ) {
            entityBuilder.code( dto.getCode() );
        }
        ...
}

 

dto 필드가 null 이 아닌 경우에만 엔티티를 변경하도록 잘 구현된 것을 볼 수 있습니다.

 

 

 

 

 

 

 

서비스단에서도 단순 entity로 치환이 아닌

값이 있는 경우 mapstruct 구현체를 한번 거치도록 하였다.

 

public class Service {

    private final Repository repository;
    private final ToMapper toMapper;

    public ResponseDTO save(DTO param) {
         Optional<Entity> entity = repository.findById(param.getIdx());
         entity.ifPresent(e -> {
             Entity.EntityBuilder builder = e.toBuilder();  // 엔티티빌더객체 변환
             toMapper.updateFromDto(param, builder);  // mapstruct 구현체 사용
             repository.save(builder.build());
         });
	...
    }
}

 

 

Entity 를 빌더객체로 변환한 후 

구현해놓은 Mapstruct updateFromDto 메소드에 전달하여 null 인 필드는 변경하지 않도록 합니다.

 

 

 

 

 

 

 

엔티티의 toBuilder 를 사용하기 위한 어노테이션 설정

 

@Builder(toBuilder = true)
public Entity(...) {...}

 

 

 

 

 

 

클라이언트에서 무분별하게 값을 보내와도 

null 로 변경되는 상황을 방지할 수 있다.

 

 

 

 

 

 



 

 

 

 

 

 

반응형
댓글
반응형
최근에 올라온 글
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Total
Today
Yesterday