티스토리 뷰

Project 댕린이집

mapstruct

xoo | 수진 2024. 2. 26. 22:09

Entity와 DTO

 

Entity

  • 엔티티는 데이터베이스 테이블에 매핑되는 객체입니다.
  • 주로 데이터베이스의 상태를 나타내고 비즈니스 로직을 포함할 수 있습니다.
  • 보통 JPA(Java Persistence API)와 함께 사용되어 데이터베이스와 상호 작용합니다.
  • 데이터베이스의 구조를 반영하고, 데이터베이스 연산(CRUD)을 수행하는 데 사용됩니다.

DTO

  • DTO는 데이터를 전송하기 위한 객체입니다.
  • 주로 클라이언트와 서버 간의 통신에서 사용됩니다.
  • 클라이언트로부터 받은 요청이나 서버에서 보내는 응답에 사용됩니다.
  • 엔티티와는 달리 비즈니스 로직을 포함하지 않으며, 주로 데이터 전송을 위한 필드를 갖습니다.

 


 

MapStruct

  • 자바 언어용 객체-객체 매핑 라이브러리입니다.
  • 자동으로 매핑 코드를 생성하여 반복적이고 지루한 매핑 작업을 줄여줍니다.
  • entity와 DTO 사이의 매핑을 수행합니다.

사용하는 이유?

  • 코드의 반복성을 줄여줍니다. ( 엔티티와 DTO 사이를 자동으로 매핑해줌 )
  • 유지보수가 용이합니다 ( 매핑 로직을 한 곳에 명시적으로 정의하여 코드를 이해하고 변경하기 쉽습니다. )
  • 타입 안전성을 보장합니다 ( 컴파일 시간에 오류를 잡아내므로 런타임 오류를 방지할 수 있습니다. )

사용법?

  1. 의존성 추가: 먼저 프로젝트에 MapStruct 의존성을 추가해야 합니다.
  2. 매핑 인터페이스 정의: 매핑할 엔티티와 DTO 간의 매핑 인터페이스를 정의합니다.
  3. 애노테이션 설정: MapStruct 애노테이션을 사용하여 매핑할 필드를 지정하고 매핑 로직을 정의합니다.
  4. 코드 생성: Maven 또는 Gradle을 사용하여 프로젝트를 빌드하면 MapStruct가 매핑 코드를 생성합니다.
  5. 매핑 사용: 생성된 매핑 클래스를 사용하여 엔티티와 DTO를 매핑합니다.

 

MapStruct의 핵심 개념

@Mapper : 매핑 인터페이스를 정의할 때 사용하는 어노테이션.

⇒ @Mapper 어노테이션을 사용하여 인터페이스를 정의하면, MapStruct는 해당 인터페이스의 구현체를 생성합니다.

@Mapping : 매핑을 정의할 때 사용하는 어노테이션.

⇒ 소스 객체와 대상 객체 간의 필드를 매핑하는 방법을 지정한다. 필드 이름이 동일한 경우 자동으로 매핑될 수 있으며, 복잡한 매핑을 위해 @Mapping 어노테이션을 사용하여 명시적으로 매핑 규칙을 지정할 수 있습니다.

@Mappings : 여러 개의 @Mapping 어노테이션을 그룹화할 때 사용하는 어노테이션.

⇒ 매핑 규칙이 여러 개인 경우 @Mappings 어노테이션을 사용하여 각각의 매핑 규칙을 지정할 수 있습니다.

@MappingTarget : 매핑 대상 객체에 해당 어노테이션을 사용하여 대상 객체를 직접 참조.

⇒ 이를 통해 기존 객체를 수정하거나 새로운 객체를 생성하지 않고 매핑을 수행할 수 있습니다.

 

 


 

 

💻 프로젝트 적용

 

1️⃣ 의존성 추가 Add Dependencies

Gradle 기준으로는 다음처럼 작성합니다.

dependencies {
    // Map Struct
    implementation 'org.mapstruct:mapstruct:1.5.3.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
    annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
}

org.mapstruct:mapstruct:1.5.3.Final

MapStruct 사용을 위한 의존성 라이브러리입니다.

org.mapstruct:mapstruct-processor:1.5.3.Final (Annotation Processor)

의존성 목록에 반드시 Annotation Processor를 추가하여야 합니다.

MapStruct는 각 데이터 매퍼(데이터 변환 인터페이스)의 클래스를 생성해 두어야 하기 때문입니다.

org.projectlombok:lombok-mapstruct-binding:0.2.0 (Annotation Processor)

롬복에서 MapStruct와 충돌을 없애기 위한 org.projectlombok:lombok-mapstruct-binding 애노테이션 프로세서를 제공합니다. 이것을 사용하지 않으면 롬복 Annotation Processor와 호출 순서 등에서 충돌이 있습니다.


2️⃣ Mapper 생성

객체 변환을 담당하는 매퍼를 생성합니다.

인터페이스만 작성해 두면 매퍼 클래스와 객체는 자동으로 생성됩니다.

package com.example.demo.mapper;

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import com.example.demo.dto.UserDTO;
import com.example.demo.entity.UserEntity;

@Mapper(componentModel = "spring")
public interface UserMapper {
	
	UserMapper instance = Mappers.getMapper(UserMapper.class);
	
	UserEntity userDTOToUserEntity(UserDTO userDTO);

}
  • @Mapper(componentModel = "spring")
    이 애노테이션은 MapStruct가 Spring Framework와 함께 사용될 수 있도록 지정합니다. 이렇게 하면 Spring의 IoC 컨테이너가 해당 매퍼 인터페이스의 구현체를 관리할 수 있습니다.
  • UserMapper instance = Mappers.getMapper(UserMapper.class);
    매퍼의 인스턴스를 생성하는 방법을 제공합니다. 이렇게 하면 매퍼 인터페이스의 메서드를 호출하여 매핑 기능을 사용할 수 있습니다.
  • UserEntity userDTOToUserEntity(UserDTO userDTO);
    UserDTO를 UserEntity로 변환하는 매핑 규칙을 정의합니다. MapStruct는 이러한 매핑 규칙을 바탕으로 실제 매핑 코드를 생성합니다.
  • @Mapping
    매핑 메서드의 구현은 MapStruct가 자동으로 생성합니다. 이를 위해서는 매핑 대상 객체의 필드명이 서로 일치해야 합니다. 필드명이 다른 경우에는 @Mapping 애노테이션을 사용하여 수동으로 매핑할 필드를 지정할 수 있습니다.
  • Mappers.getMapper()
    MapStruct가 제공하는 Mappers.getMapper() 메서드를 사용하면 매퍼 인스턴스를 얻을 수 있습니다. 이렇게 생성된 매퍼 인스턴스를 사용하여 매핑을 수행할 수 있습니다.

3️⃣ Mapper 사용

UserService.java

package com.example.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.dto.UserDTO;
import com.example.demo.entity.UserEntity;
import com.example.demo.mapper.UserMapper;
import com.example.demo.repository.UserRepository;

@Service
public class UserService {
	
	@Autowired
	private UserRepository userRepository;

	// 아이디 중복 검사
	public Object idCheck(String userId) throws Exception {
		// 사용자 아이디가 빈 문자열인 경우 예외를 던짐
		if(userId.equals("")) {
			throw new Exception(); 
		}
		// UserRepository를 사용하여 주어진 사용자 아이디의 중복 여부를 확인
		return userRepository.existsByUserId(userId);
	}
	
	// 회원가입
	public Object register(UserDTO userDTO) {
		// userDTO -> userEntity 로 변형하는 맵핑이 필요함.
		// mapper mapstruct
		UserEntity userEntity = UserMapper.instance.userDTOToUserEntity(userDTO);
		return userRepository.save(userEntity);
	}
	
}

 

 


 

 

💣 ClassNotFoundException

위 코드의 상태로 실행해봤더니 해당 이슈가 발생했습니다..

java.lang.ClassNotFoundException: Cannot find implementation for com.example.demo.mapper.UserMapper

 

원인?

맵스트럭트가 해당 매퍼의 구현체를 찾을 수 없을 때 발생합니다. 이 오류가 발생하는 이유는 스프링이 맵스트럭트를 인식하지 못하는 경우입니다.

 

아직 해결 방법을 찾지 못했는데 구글링 해보니 워낙 맵스트럭트가 버그가 많다고 합니다..조금 더 알아보고 해결된다면, 다음에는 이에 대한 해결 방법을 기록해보겠습니다!

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/07   »
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
글 보관함