Develop/Java

[Java] MapStruct로 간편하게 객체 매핑하기

DevPi 2024. 9. 23. 09:01
반응형

Spring Boot를 사용하면서 DTO(Data Transfer Object)와 Entity 간의 매핑은 흔히 발생하는 작업입니다. 이러한 매핑을 직접 구현하는 것은 번거롭고, 코드가 중복되기 쉽습니다. MapStruct는 이러한 문제를 해결해주는 강력한 매핑 프레임워크로, 코드 작성을 최소화하면서 성능 좋은 매핑 코드를 자동으로 생성해 줍니다. 이번 포스트에서는 MapStruct의 개념과 간단한 예제를 통해 Spring Boot에서 어떻게 활용할 수 있는지 알아보겠습니다.


MapStruct란?

MapStruct는 Java에서 컴파일 타임에 매핑 코드를 생성하여 런타임 성능을 최적화하는 매핑 라이브러리입니다. DTO와 Entity 간의 변환이 필요한 경우, MapStruct를 사용하면 매핑 코드를 수동으로 작성할 필요 없이 간단한 인터페이스와 어노테이션만으로 매핑 로직을 자동으로 생성할 수 있습니다.

 

MapStruct의 주요 특징

  • 컴파일 타임 코드 생성 : 런타임이 아닌 컴파일 시점에 매핑 코드를 생성하여 성능이 뛰어납니다.
  • 간결한 코드 : 매핑 로직을 간단한 어노테이션과 인터페이스로 정의할 수 있어 코드 중복을 줄일 수 있습니다.
  • 자동 변환 지원 : 기본 타입 변환, 컬렉션 매핑 등을 자동으로 처리합니다.
  • Spring과의 쉬운 통합 : @Mapper 어노테이션과 componentModel = "spring" 옵션을 통해 Spring Bean으로 등록할 수 있습니다.

간단한 예시: DTO와 Entity 매핑하기

아래 예시에서는 UserEntity와 UserDTO 간의 매핑을 MapStruct를 이용하여 구현해 보겠습니다.

 

1. 프로젝트 의존성 추가

먼저, build.gradle에 MapStruct 관련 의존성을 추가합니다.

dependencies {
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
}

의존성 추가 후, ./gradlew build 명령어로 프로젝트를 빌드하여 MapStruct가 매핑 코드를 생성하도록 합니다.

 

2. DTO와 Entity 클래스 생성

UserEntity와 UserDTO 클래스를 생성하여 매핑할 대상이 되는 데이터를 정의합니다.

// UserEntity.java
package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {
    private Long id;
    private String name;
    private String email;
}
// UserDTO.java
package com.example.demo.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
    private String name;
    private String email;
}

 

3. MapStruct 매퍼 인터페이스 생성

MapStruct를 사용하여 UserEntity와 UserDTO 간의 매핑을 정의하는 인터페이스를 만듭니다.

// UserMapper.java
package com.example.demo.mapper;

import com.example.demo.dto.UserDTO;
import com.example.demo.entity.UserEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper(componentModel = "spring") // Spring Bean으로 등록
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    // Entity to DTO 매핑
    UserDTO toDto(UserEntity entity);

    // DTO to Entity 매핑
    @Mapping(target = "id", ignore = true) // 매핑 시 ID 필드는 무시
    UserEntity toEntity(UserDTO dto);
}

위 코드에서는 @Mapper(componentModel = "spring")을 사용하여 매퍼를 Spring Bean으로 등록할 수 있습니다. @Mapping 어노테이션은 특정 필드 매핑 시 설정을 정의하는데, 위 예시에서는 id 필드를 무시하고 매핑하도록 설정하였습니다.

 

4. 서비스에서 매퍼 사용하기

이제 매핑된 객체를 서비스에서 활용해 보겠습니다.

// UserService.java
package com.example.demo.service;

import com.example.demo.dto.UserDTO;
import com.example.demo.entity.UserEntity;
import com.example.demo.mapper.UserMapper;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private final UserMapper userMapper;

    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public UserDTO getUserDto() {
        // 예제 엔티티 생성
        UserEntity userEntity = new UserEntity(1L, "John Doe", "john@example.com");

        // Entity를 DTO로 변환
        return userMapper.toDto(userEntity);
    }

    public UserEntity createUser(UserDTO userDTO) {
        // DTO를 Entity로 변환하여 사용
        return userMapper.toEntity(userDTO);
    }
}

 

5. 컨트롤러에서 매핑된 결과 확인하기

컨트롤러를 통해 서비스 메서드를 호출하고 매핑 결과를 확인합니다.

// UserController.java
package com.example.demo.controller;

import com.example.demo.dto.UserDTO;
import com.example.demo.entity.UserEntity;
import com.example.demo.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user")
    public UserDTO getUser() {
        return userService.getUserDto();
    }

    @PostMapping("/user")
    public UserEntity createUser(@RequestBody UserDTO userDTO) {
        return userService.createUser(userDTO);
    }
}

마무리

MapStruct는 DTO와 Entity 간의 매핑을 간편하게 구현할 수 있게 해주는 강력한 도구입니다. 매핑 코드를 자동으로 생성하여 코드의 중복을 줄이고, 컴파일 타임에 성능 최적화된 코드를 제공합니다. 특히 Spring Boot와의 통합이 쉽고, 유지 보수도 간편하여 개발 생산성을 크게 향상시킬 수 있습니다.

이번 포스트에서는 기본적인 MapStruct 사용법을 소개했지만, MapStruct의 다양한 기능을 활용하면 더욱 정교하고 복잡한 매핑도 손쉽게 처리할 수 있습니다. MapStruct를 활용하여 매핑 코드를 효율적으로 관리해 보세요!

반응형