Spring Boot

[Spring Boot] MapStruct 라이브러리로 엔티티 ↔ DTO 변환 자동으로 매핑하기 (예제 코드)

공대생안씨 2024. 8. 14. 22:41

1. MapStruct 란?

  • 자바 bean 유형 간 (ex. DTO ↔ Entity간) 의 매핑코드를 자동으로 생성하는 라이브러리
  • 컴파일 시점에 매핑 코드 자동 생성 → 런타임에서 안정성 보장
  • 반복되는 객체 매핑에서 발생할 수 있는 오류 줄일 수 있음

 

2. 사용 방법

2-1. dependency (의존성) 추가

  • build.gradle
dependencies {
    ...
    implementation 'org.mapstruct:mapstruct:1.5.3.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
    ...
}
📌 주의

Lombok 라이브러리에 먼저 의존성 추가가 되어 있어야 함

MapStruct : Lombok의 getter, setter, builder 를 이용하여 생성됨 ⇒ Lombok보다 먼저 의존성이 선언된 경우 실행 불가!

 

2-2. DTO, Entity 코드

// Entity 클래스

@Entity
public class User {
    private Long id;
    private String name;
    private String email;
    private String password;
}
// User DTO 클래스
public class UserDto {
    private String name;
    private String email;
}

 

2-3. Interface 생성

2-3-1. Interface 생성 (일대일)

@Mapper(componenetModel = "spring") // componentModel 생략 가능
public interface UserMapper {
		
    // 매퍼 클래스에서 해당 인터페이스 (UserMapper)를 찾게 해줌
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
	
    UserDto toDto(User user);
    User toEntity(UserDto userDto);
}

⇒ 컬럼명이 다른경우 직접 지정 → @Mapping(source=”source 필드명”, target=”target 필드명”)

 

  • MapStruct 라이브러리가 UserMapper 인터페이스를 기반으로 아래의 구현 클래스를 자동 생성함
import org.springframework.stereotype.Component;

@Component
public class UserMapperImpl implements UserMapper {

    @Override
    public UserDto toDto(User user) {
        if (user == null) {
            return null;
        }

        UserDto userDto = new UserDto();
        userDto.setName(user.getName());
        userDto.setEmail(user.getEmail());

        return userDto;
    }

    @Override
    public User toEntity(UserDto userDto) {
        if (userDto == null) {
            return null;
        }

        User user = new User();
        user.setName(userDto.getName());
        user.setEmail(userDto.getEmail());

        return user;
    }
}

⇒ 해당 구현체는 빌드 시 build/classes/java/main에 매핑 인터페이스가 위치한 곳에 만들어짐!

 

2-3-2. Interface 생성 (다대일)

  • 여러 객체를 하나의 객체에 매핑하는 경우
public interface MessageMapper {

    MessageMapper INSTANCE = Mappers.getMapper(MessageMapper.class);

    // PageDto, RequestDto -> MessageServiceDto 매핑
    @Mapping(source="pageDto.pageIndex", target="pageIdx")
    @Mapping(source="pageDto.pageCount", target="pageCnt")
    MessageServiceDto toMessageServiceDto(PageDto pageDto, RequestDto requestDto);
}

 

2-4. 매핑 사용

  • 사용 예시 코드
@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;
    
    @Autowired
    private UserMapper userMapper;  // UserMapper를 주입받음
    
    public UserDto getUser(Long id) {
        User user = userRepository.findById(id);
        return userMapper.toDto(user);  // UserMapper 사용 -> DTO로 변환
    }
    
    public void saveUser(UserDto userDto) {
        User user = userMapper.toEntity(userDto); // UserMapper 사용 -> 엔티티로 변환
        userRepository.save(user);
    }
}