### ModelMapper 소개 및 사용 방법

ModelMapper는 자바에서 객체 간 매핑을 간편하게 처리할 수 있도록 도와주는 오픈소스 라이브러리입니다. DTO(Data Transfer Object)와 엔티티(Entity) 간의 변환 작업을 수동으로 작성하는 대신, ModelMapper를 사용하면 코드의 중복을 줄이고 가독성을 높일 수 있습니다. 이 라이브러리는 객체의 필드 이름과 타입을 기반으로 자동 매핑을 수행하며, 필요에 따라 사용자 정의 매핑 규칙을 추가할 수도 있습니다.

ModelMapper의 주요 특징은 다음과 같습니다:

- **자동 매핑**: 필드 이름이 동일하면 별도의 설정 없이 매핑 가능.
- **유연성**: 복잡한 매핑 요구사항을 커스터마이징 가능.
- **간결함**: boilerplate 코드를 줄여 개발 생산성 향상.

---

### 의존성 추가

ModelMapper를 사용하려면 먼저 프로젝트에 의존성을 추가해야 합니다. Maven을 사용하는 경우 `pom.xml`에 다음 코드를 추가하세요:

```xml
<dependency>
    <groupId>org.modelmapper</groupId>
    <artifactId>modelmapper</artifactId>
    <version>3.2.0</version> <!-- 최신 버전 확인 필요 -->
</dependency>
```

Gradle을 사용하는 경우 `build.gradle`에 아래를 추가합니다:

```gradle
implementation 'org.modelmapper:modelmapper:3.2.0' // 최신 버전 확인 필요
```

---

### 기본 사용 예시

아래는 ModelMapper를 사용해 간단한 객체 간 매핑을 수행하는 예제입니다.

#### 1. 엔티티와 DTO 클래스 정의

먼저 매핑할 두 클래스를 정의합니다:

```java
// 엔티티 클래스
public class User {
    private Long id;
    private String name;
    private String email;

    // Getter와 Setter
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

// DTO 클래스
public class UserDTO {
    private Long id;
    private String name;
    private String email;

    // Getter와 Setter
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}
```

#### 2. ModelMapper로 매핑

이제 ModelMapper를 사용해 `User` 객체를 `UserDTO`로 변환해봅시다:

```java
import org.modelmapper.ModelMapper;

public class Main {
    public static void main(String[] args) {
        // ModelMapper 인스턴스 생성
        ModelMapper modelMapper = new ModelMapper();

        // User 객체 생성 및 데이터 설정
        User user = new User();
        user.setId(1L);
        user.setName("홍길동");
        user.setEmail("hong@example.com");

        // User -> UserDTO로 매핑
        UserDTO userDTO = modelMapper.map(user, UserDTO.class);

        // 결과 출력
        System.out.println("ID: " + userDTO.getId());
        System.out.println("Name: " + userDTO.getName());
        System.out.println("Email: " + userDTO.getEmail());
    }
}
```

**출력 결과:**

```
ID: 1
Name: 홍길동
Email: hong@example.com
```

위 예제에서 `modelMapper.map()` 메서드는 `User` 객체의 필드를 `UserDTO`로 자동으로 매핑합니다. 필드 이름과 타입이 동일하기 때문에 별도의 설정 없이도 동작합니다.

---

### 고급 사용 예시: 커스터마이징 매핑

필드 이름이 다르거나 특정 변환 로직이 필요한 경우, ModelMapper의 설정을 커스터마이징할 수 있습니다.

#### 1. 필드 이름이 다른 경우

예를 들어, `User` 클래스의 `email` 필드를 `UserDTO`의 `emailAddress`로 매핑한다고 가정해봅시다.

```java
// 수정된 UserDTO 클래스
public class UserDTO {
    private Long id;
    private String name;
    private String emailAddress; // 필드 이름 변경

    // Getter와 Setter
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmailAddress() { return emailAddress; }
    public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; }
}
```

#### 2. 커스터마이징 매핑 설정

ModelMapper에 매핑 규칙을 추가합니다:

```java
import org.modelmapper.ModelMapper;
import org.modelmapper.PropertyMap;

public class Main {
    public static void main(String[] args) {
        // ModelMapper 인스턴스 생성
        ModelMapper modelMapper = new ModelMapper();

        // 커스터마이징 매핑 규칙 추가
        modelMapper.addMappings(new PropertyMap<User, UserDTO>() {
            @Override
            protected void configure() {
                map().setEmailAddress(source.getEmail()); // email -> emailAddress
            }
        });

        // User 객체 생성
        User user = new User();
        user.setId(1L);
        user.setName("홍길동");
        user.setEmail("hong@example.com");

        // 매핑 수행
        UserDTO userDTO = modelMapper.map(user, UserDTO.class);

        // 결과 출력
        System.out.println("ID: " + userDTO.getId());
        System.out.println("Name: " + userDTO.getName());
        System.out.println("Email Address: " + userDTO.getEmailAddress());
    }
}
```

**출력 결과:**

```
ID: 1
Name: 홍길동
Email Address: hong@example.com
```

---

### 추가 기능: 리스트 매핑

여러 객체를 포함한 리스트를 매핑할 수도 있습니다:

```java
import org.modelmapper.ModelMapper;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        ModelMapper modelMapper = new ModelMapper();

        // User 리스트 생성
        List<User> users = Arrays.asList(
            new User(1L, "홍길동", "hong@example.com"),
            new User(2L, "김영희", "kim@example.com")
        );

        // 리스트 매핑
        List<UserDTO> userDTOs = users.stream()
            .map(user -> modelMapper.map(user, UserDTO.class))
            .collect(Collectors.toList());

        // 결과 출력
        userDTOs.forEach(dto -> System.out.println(dto.getName() + ": " + dto.getEmail()));
    }
}
```

**출력 결과:**

```
홍길동: hong@example.com
김영희: kim@example.com
```

---

### 결론

ModelMapper는 객체 간 매핑을 단순화하고 개발자의 시간을 절약해주는 강력한 도구입니다. 기본적인 자동 매핑부터 복잡한 커스터마이징까지 지원하므로, 프로젝트 요구사항에 따라 적절히 활용할 수 있습니다. 위 예제를 참고하여 실제 프로젝트에 적용해보세요! 추가 질문이 있다면 언제든 물어보세요.