Server/Spring Boot

MapStruct 의 다양한 사용에 대해 알아보자

hoonylab 2025. 4. 16. 13:08
728x90
반응형

🚀 MapStruct 고급 매핑 예제

이번엔 MapStruct를 좀 더 깊이 있게 사용하는 예제들을 소개합니다.
List 매핑, @AfterMapping, @Named, @InheritInverseConfiguration 등 실제 프로젝트에서도 매우 유용한 기능들이에요.


1️⃣ List 매핑

컬렉션 타입도 자동 매핑 가능합니다.

// 단일 DTO 매핑 메서드
UserDto toDto(User user);

// 리스트 매핑
List<UserDto> toDtoList(List<User> users);

단, 단일 객체 매핑 메서드가 정의되어 있어야 리스트 매핑도 동작합니다.

---

2️⃣ @AfterMapping - 매핑 후 추가 작업 처리

매핑이 완료된 후 후처리를 하고 싶을 경우 @AfterMapping을 사용합니다.

@Mapper(componentModel = "spring")
public interface UserMapper {

    UserDto toDto(User user);

    @AfterMapping
    default void setCustomFields(@MappingTarget UserDto dto, User user) {
        dto.setUsername(dto.getUsername().toUpperCase());
    }
}
  • @MappingTarget: 결과 객체를 참조합니다.
  • 위 예시에서는 매핑된 결과 중 username 필드를 대문자로 수정합니다.

---

3️⃣ @Named - 재사용 가능한 매핑 정의

@Named는 재사용 가능한 변환 메서드를 만들고, qualifiedByName으로 명시적으로 사용할 때 유용합니다.

@Mapper(componentModel = "spring")
public interface UserMapper {

    @Mapping(source = "email", target = "email", qualifiedByName = "maskEmail")
    UserDto toDto(User user);

    @Named("maskEmail")
    static String maskEmail(String email) {
        if (email == null || !email.contains("@")) return email;
        return "***@" + email.substring(email.indexOf("@") + 1);
    }
}

포인트: 민감 정보를 가릴 때, 포맷을 바꿀 때 유용하게 사용됩니다.

---

4️⃣ @InheritInverseConfiguration - 양방향 매핑 간소화

@InheritInverseConfiguration기존 매핑 설정을 반대로 재사용할 수 있게 해줍니다.

@Mapper(componentModel = "spring")
public interface UserMapper {

    @Mapping(source = "name", target = "username")
    UserDto toDto(User user);

    @InheritInverseConfiguration
    User toEntity(UserDto dto);
}

장점: 중복되는 @Mapping을 줄이고, 실수를 방지할 수 있어요.

---

5️⃣ 여러 기능을 조합한 예제

@Mapper(componentModel = "spring")
public interface UserMapper {

    @Mapping(source = "name", target = "username")
    @Mapping(source = "email", target = "email", qualifiedByName = "maskEmail")
    UserDto toDto(User user);

    @InheritInverseConfiguration
    @Mapping(target = "id", ignore = true)
    User toEntity(UserDto dto);

    List<UserDto> toDtoList(List<User> users);

    @Named("maskEmail")
    static String maskEmail(String email) {
        if (email == null || !email.contains("@")) return email;
        return "***@" + email.substring(email.indexOf("@") + 1);
    }

    @AfterMapping
    default void afterMapping(@MappingTarget UserDto dto, User user) {
        dto.setUsername(dto.getUsername().toUpperCase());
    }
}

---

🧠 마무리 정리

  • List 매핑은 단일 매핑 메서드가 있을 때 자동 지원됨
  • @AfterMapping은 후처리 로직 작성에 유용
  • @Named + qualifiedByName은 커스텀 메서드 재사용 시 필수
  • @InheritInverseConfiguration은 양방향 매핑을 편리하게 관리

이렇게 MapStruct의 기능을 적절히 조합하면, 반복 코드를 줄이면서도 확장성과 가독성을 높일 수 있습니다 😎

728x90
반응형