스프링

 

1. Spring Boot Actuator

 

 

개요

  • Spring Boot Actuator는 Spring Boot 애플리케이션의 운영 가능성을 높이는 다양한 기능을 제공합니다.
  • 애플리케이션의 모니터링과 관리를 가능하게 해줍니다.

사용 방법

  1. 의존성 추가:

    • Spring Boot Starter Actuator를 추가해야 합니다.
    • pom.xml에서 해당 의존성을 추가 후, 웹 관련 기능을 actuator로 변경합니다.

 

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

 

 

  1. 엔드포인트:

    • Actuator는 다양한 엔드포인트를 통해 애플리케이션 정보를 제공합니다.
      • /actuator/beans: 애플리케이션의 Spring 빈 목록을 표시.
      • /actuator/health: 애플리케이션의 상태 정보.
      • /actuator/metrics: 애플리케이션 관련 메트릭.
      • /actuator/mappings: 요청 매핑에 관한 세부 정보.

기본 설정

  • Actuator의 기본 설정으로는 애플리케이션 상태 정보만 제공됩니다.
  • 더 많은 정보를 공개하려면 src/main/resources/application.properties 파일에 다음을 추가:

 

주요 엔드포인트 설명

  1. /actuator/beans

    • 로드된 모든 Spring 빈의 정보 제공.
    • 빈의 스코프, 타입, 위치 및 의존성을 확인할 수 있습니다.
  2. /actuator/env

    • 애플리케이션의 실행 환경에 대한 세부 정보 제공.
    • 사용 중인 포트, Java 버전, 클래스 경로 등을 확인할 수 있습니다.
  3. /actuator/metrics

    • 애플리케이션이 추적하는 다양한 메트릭 제공.
    • 예를 들어, HTTP 요청 수, 실행 시간, 응답 상태 등의 세부 정보를 확인할 수 있습니다.
  4. /actuator/mappings

    • 정의된 모든 컨트롤러의 요청 메서드와 URI를 확인할 수 있습니다.
    • 각 요청 메서드에 대한 세부 정보를 볼 수 있습니다.

결론

  • Spring Boot Actuator는 애플리케이션 운영 환경을 모니터링하고 관리하는 데 유용한 도구입니다.
  • 다양한 엔드포인트를 통해 애플리케이션의 상태, 메트릭, 빈, 환경 정보 등을 손쉽게 확인할 수 있습니다.

 

 

application-prod.properties  설정

 

# Actuator 설정 (운영 환경에서 노출 범위 제한)
management.endpoints.web.exposure.include=info,health

 

설정의 의미

이 설정은 Spring Boot Actuator의 웹 엔드포인트 중에서 **운영 환경(production)**에서 **어떤 엔드포인트를 노출(expose)**할지를 지정합니다. 구체적으로, 위 설정은 info와 health 두 가지 엔드포인트만 외부에 공개하도록 제한하는 역할을 합니다.

 

세부 설명

  1. Actuator 엔드포인트란?

    • Spring Boot Actuator는 애플리케이션의 상태, 메트릭, 환경 설정 등을 모니터링하고 관리할 수 있는 다양한 엔드포인트를 제공합니다.
    • 예를 들어, /actuator/health, /actuator/metrics, /actuator/beans 등이 있습니다.
  2. management.endpoints.web.exposure.include 속성:

    • 이 속성은 웹을 통해 접근 가능한 Actuator 엔드포인트를 지정합니다.
    • include에 나열된 엔드포인트만 외부에서 접근할 수 있게 됩니다.
  3. info와 health 엔드포인트:

    • /actuator/info: 애플리케이션의 일반적인 정보를 제공합니다. 주로 애플리케이션의 버전, 빌드 정보 등을 포함합니다.
    • /actuator/health: 애플리케이션의 현재 상태를 확인할 수 있는 엔드포인트로, 주로 시스템의 건강 상태(예: 데이터베이스 연결 여부 등)를 반환합니다.

 

왜 제한할까요?

운영 환경에서는 보안 및 성능 측면에서 필요한 정보만을 외부에 공개하는 것이 중요합니다. 모든 Actuator 엔드포인트를 외부에 노출하면 다음과 같은 문제가 발생할 수 있습니다:

  • 보안 위험: 민감한 정보(예: 빈 목록, 환경 변수 등)가 외부에 노출될 수 있습니다.
  • 성능 문제: 불필요한 엔드포인트 접근으로 인해 서버 자원이 낭비될 수 있습니다.

따라서, 운영 환경에서는 필요 최소한의 엔드포인트만을 공개하여 보안을 강화하고, 불필요한 리소스 사용을 줄이는 것이 좋습니다.

운영 환경에서의 권장 설정

운영 환경에서는 일반적으로 health와 info 엔드포인트만을 공개하는 것이 권장됩니다. 추가적으로, 필요에 따라 다른 엔드포인트를 선택적으로 공개할 수 있습니다. 예를 들어, 모니터링 도구와의 연동을 위해 metrics 엔드포인트를 추가로 공개할 수 있습니다.

 

management.endpoints.web.exposure.include=info,health,metrics


 

추가 보안 강화 방법

  • 인증 및 권한 부여: Actuator 엔드포인트에 접근할 수 있는 사용자나 서비스에 대해 인증 및 권한을 설정합니다.
  • 방화벽 설정: 외부에서 접근할 수 없는 네트워크 내에서만 Actuator를 사용할 수 있도록 방화벽을 설정합니다.
  • HTTPS 사용: Actuator 엔드포인트 접근 시 HTTPS를 사용하여 데이터 전송의 보안을 강화합니다.

결론

management.endpoints.web.exposure.include=info,health 설정은 운영 환경에서 Actuator의 노출 범위를 info와 health로 제한하여 보안을 강화하고, 불필요한 리소스 사용을 방지하는 중요한 설정입니다. 운영 환경에서는 필요한 최소한의 정보만을 공개하고, 나머지 엔드포인트는 안전하게 비공개로 유지하는 것이 최선의 보안 관행입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.HAL Explorer

 

1. HAL이란?

  • HAL (Hypertext Application Language): JSON 기반 포맷으로, API 리소스 간 하이퍼링크를 제공하는 간단한 포맷입니다.
  • API에서 _links 항목에 모든 링크가 정의됩니다.

2. HAL Explorer란?

  • HAL Explorer는 HAL을 사용하는 RESTful 하이퍼미디어 API를 탐색할 수 있는 API 탐색 도구입니다.
  • HAL을 사용하는 API라면 HAL Explorer를 통해 쉽게 탐색할 수 있습니다.
  • API를 탐색할 수 있어 비전문가도 쉽게 활용할 수 있다는 장점이 있습니다.

3. HAL Explorer 사용 방법

  • Spring Boot 프로젝트에 HAL Explorer 추가하기

pom.xml에 다음 의존성을 추가합니다

 

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-rest-hal-explorer</artifactId>
</dependency>

 

그래들

.

implementation 'org.springframework.data:spring-data-rest-hal-explorer'


 

 

 

4. HAL Explorer 실행

  • 애플리케이션을 실행한 후   http://localhost:8080/explorer/index.html 으로 접속하면 HAL Explorer가 열립니다.
  •  
  • 예를 들어 /actuator 엔드포인트에 접근하면, HAL Explorer가 링크와 데이터를 표시해줍니다.

5. HAL Explorer 기능

  • 링크 탐색: 엔드포인트로 GET 요청을 보내 API의 상세 데이터를 볼 수 있습니다.
  • 데이터와 링크 확인: API에서 반환하는 데이터와 하이퍼링크를 모두 탐색할 수 있습니다.

HAL Explorer를 사용하면 API의 리소스와 관계를 쉽게 파악할 수 있습니다. API가 HAL을 지원하는 경우, HAL Explorer는 매우 유용한 탐색 도구가 됩니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

3. MapStruct 설정

 

 

1. MapStruct란?

 

MapStruct는 Java 애플리케이션에서 객체 간의 매핑을 자동화해주는 컴파일 타임 매핑 프레임워크입니다.

주로 엔티티와 DTO 간의 변환 작업을 단순화하고, 코드 중복을 줄이며, 성능을 향상시키는 데 사용됩니다.

 

MapStruct의 주요 특징:

  • 컴파일 타임 매핑: 런타임 대신 컴파일 시점에 매핑 코드를 생성하여 성능을 최적화.
  • 간단한 설정: 최소한의 설정으로 복잡한 매핑 로직을 구현할 수 있음.
  • 유연성: 커스텀 매핑, 표현식, 어노테이션 등을 통해 세밀한 매핑 제어 가능.

 

 

의존성 추가 (pom.xml)

<dependencies>
    <!-- MapStruct 의존성 추가 -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.3.Final</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.5.3.Final</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <!-- MapStruct 애노테이션 프로세서 설정 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.10.1</version>
            <configuration>
                <source>17</source>
                <target>17</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>1.5.3.Final</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

 

build.gradle (Groovy DSL)

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

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

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

tasks.withType(JavaCompile) {
    options.annotationProcessorPath = configurations.annotationProcessor
}

 

build.gradle.kts (Kotlin DSL)

plugins {
    java
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.mapstruct:mapstruct:1.5.3.Final")
    annotationProcessor("org.mapstruct:mapstruct-processor:1.5.3.Final")
}

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

tasks.withType<JavaCompile> {
    options.annotationProcessorPath = configurations.annotationProcessor.get()
}

 

 

 

 

MapStruct를 이용한 TodoMapper 클래스

package net.macaronics.springboot.webapp.mapper;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import net.macaronics.springboot.webapp.dto.todo.TodoResponseDTO;
import net.macaronics.springboot.webapp.entity.Todo;

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

    @Mapping(source = "user.username", target = "username")
    TodoResponseDTO toResponseDTO(Todo todo);

    // 필요에 따라 다른 매핑 메서드도 추가
    // Todo toEntity(TodoRequestDTO dto);
}

 

MapStruct를 사용하면, 인터페이스 기반으로 매핑 메서드를 정의하고, 컴파일 시점에 매핑 구현체가 자동으로 생성됩니다.

componentModel = "spring" 설정을 통해 Spring의 빈으로 등록됩니다.

 

서비스 계층에서 MapStruct Mapper 사용

@Service
@RequiredArgsConstructor
public class TodoService {

    private final TodoRepository todoRepository;
    private final TodoMapper todoMapper;

    @Transactional(readOnly = true)
    public List<TodoResponseDTO> getAllTodos() {
        List<Todo> todos = todoRepository.findAll();
        return todos.stream()
                .map(todoMapper::toResponseDTO)
                .collect(Collectors.toList());
    }

    // 다른 서비스 메서드들...
}

 

 

 

 

 

 

2. @Mapping 어노테이션 이해하기

@Mapping 어노테이션은 MapStruct에서 매핑 규칙을 정의할 때 사용됩니다. 이 어노테이션을 통해 소스 객체의 특정 필드타겟 객체의 다른 필드로 매핑할 수 있습니다.

주요 속성:

  • source: 매핑할 소스 객체의 필드 경로를 지정.
  • target: 매핑할 타겟 객체의 필드를 지정.

 

 

 

3. 구체적인 예제 분석

엔티티와 DTO 구조

Todo 엔티티:

@Entity
@Data
@Table(name = "todos")
@AllArgsConstructor
@Builder
@NoArgsConstructor
public class Todo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "todo_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    private String description;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate targetDate;

    private boolean done;
    
    // DTO 변환 메서드는 별도의 Mapper 클래스에 위임
}

 

TodoResponseDTO DTO:

@Data
@Builder
public class TodoResponseDTO {
    private Long id;
    private String username;
    private String description;
    private LocalDate targetDate;
    private boolean done;
}

 

매핑 로직 설명

목표: Todo 엔티티의 user.username 필드를 TodoResponseDTO의 username 필드로 매핑.

@Mapping 어노테이션 사용:

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

    @Mapping(source = "user.username", target = "username")
    TodoResponseDTO toResponseDTO(Todo todo);
    
    // 필요한 경우 다른 매핑 메서드 추가
}

 

어노테이션의 역할:

  • source = "user.username": Todo 엔티티의 user 필드(즉, User 객체)의 username 필드를 소스로 지정.
  • target = "username": TodoResponseDTO의 username 필드로 매핑.

매핑 전과 후 비교

매핑 전:

  • Todo 엔티티는 User 객체를 포함하고 있으며, username은 User 객체 내부에 있습니다.
  • TodoResponseDTO는 username 필드를 직접 포함하고 있습니다.

매핑 후:

  • Todo 엔티티의 user.username 값이 TodoResponseDTO의 username 필드에 할당됩니다.
  • 결과적으로, DTO는 User 객체를 직접 포함하지 않고, username만을 노출합니다.

실제 매핑 코드 생성 예시

MapStruct는 컴파일 시점에 다음과 같은 구현 코드를 자동으로 생성합니다:

 

@Component
public class TodoMapperImpl implements TodoMapper {

    @Override
    public TodoResponseDTO toResponseDTO(Todo todo) {
        if ( todo == null ) {
            return null;
        }

        TodoResponseDTO.TodoResponseDTOBuilder todoResponseDTO = TodoResponseDTO.builder();

        todoResponseDTO.id( todo.getId() );
        if ( todo.getUser() != null ) {
            todoResponseDTO.username( todo.getUser().getUsername() );
        }
        todoResponseDTO.description( todo.getDescription() );
        todoResponseDTO.targetDate( todo.getTargetDate() );
        todoResponseDTO.done( todo.isDone() );

        return todoResponseDTO.build();
    }
}

 

설명:

  • todo.getUser().getUsername()를 통해 User 객체의 username 값을 가져와 TodoResponseDTO의 username 필드에 설정.
  • User 객체가 null일 경우, username 필드는 null로 설정됨.

 

 

1) 모든 필드 매핑 가능 여부:

  • @Mapping(source = "user.email", target = "email")와 같이 소스 객체의 필드를 대상 객체의 필드로 매핑할 수 있습니다. 필드 이름은 고유할 필요가 없으며, 각 필드의 이름이 다르더라도 매핑이 가능합니다.
  • 예를 들어, user 객체에 nickname 필드가 있고, DTO에 nick이라는 필드가 있다면, 다음과 같이 매핑할 수 있습니다:

 

@Mapping(source = "user.nickname", target = "nick")



 

2) 여러 매핑 지정 가능 여부:

  • 여러 개의 매핑을 지정하는 것은 가능합니다. 여러 개의 @Mapping 어노테이션을 사용하여 매핑할 수 있습니다. 예를 들어:
@Mapping(source = "user.username", target = "username")
@Mapping(source = "user.nickname", target = "nick")
TodoResponseDTO toResponseDTO(Todo todo);

 

  • 3) @Mapper(componentModel = "spring")의 이유:

    • componentModel = "spring" 설정을 통해 생성된 매퍼 클래스가 Spring의 빈으로 등록됩니다. 이를 통해 Spring의 의존성 주입을 활용할 수 있습니다. 이름은 프로젝트의 요구에 따라 다르게 설정할 수 있으며, 고유해야 할 필요는 없습니다.
    • 다른 이름을 지정하려면 @Mapper 어노테이션에 원하는 이름을 넣어주면 됩니다. 그러나 일반적으로 Spring 빈의 이름은 클래스 이름을 기반으로 자동으로 생성되므로, 특별히 다른 이름을 지정할 필요가 없다면 기본적으로 사용해도 무방합니다.
  •  
  •  
  •  
  • 4) 반대 매핑:

    •  반대로 매핑하는 것도 가능합니다. 예를 들어, TodoFromRequestDTO 객체를 Todo 객체로 매핑할 수 있습니다:

 

@Mapping(source = "username", target = "user.username")
Todo ofTodo(TodoFromRequestDTO todoFromRequestDTO);

 

 

 

 

 

 

 

 

 

 

 

4. 왜 @Mapping(source = "user.username", target = "username")가 필요한가?

 

필드 이름이 다른 경우:

  • Todo 엔티티의 User 객체 내부에 있는 username 필드를 TodoResponseDTO의 username 필드로 매핑할 때, 직접적인 필드 이름 매칭이 불가능합니다.
  • MapStruct는 기본적으로 필드 이름이 동일한 경우 자동 매핑을 수행하지만, 다른 경로에 있는 필드이름이 다른 필드는 명시적으로 매핑을 지정해야 합니다.

복잡한 객체 구조:

  • Todo 엔티티는 User 객체와 다대일 관계를 가지고 있어, User 객체의 필드를 중첩된 형태로 접근해야 합니다.
  • DTO는 더 단순화된 구조로, User 객체를 직접 포함하지 않고 필요한 필드(username)만을 노출.

명확한 매핑 규칙:

  • @Mapping 어노테이션을 사용하여 매핑 규칙을 명시적으로 정의하면, 코드의 가독성과 유지보수성이 향상됩니다.
  • 팀 내 다른 개발자들도 매핑 규칙을 쉽게 이해하고, 변경 사항을 추적할 수 있습니다.

 

 

 

 

5. 추가적인 매핑 옵션

MapStruct는 다양한 매핑 옵션과 기능을 제공합니다. 몇 가지 유용한 기능을 소개합니다.

 

a. 기본 매핑 (Default Mapping):

MapStruct는 필드 이름이 동일한 경우 자동으로 매핑을 수행합니다.

@Mapper(componentModel = "spring")
public interface UserMapper {
    UserDTO toUserDTO(User user);
}

 

위 예제에서 User 엔티티와 UserDTO의 필드 이름이 동일하면, 자동으로 매핑됩니다.

 

 

b. 커스텀 매핑 (Custom Mapping):

필드 이름이 다르거나, 변환 로직이 필요한 경우 @Mapping 어노테이션을 사용합니다.

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

    @Mapping(source = "userRole", target = "role")
    UserDTO toUserDTO(User user);
}

 

userRole 필드를 role 필드로 매핑.

 

 

c. 표현식 사용 (Expression):

필드 변환 시 표현식을 사용하여 복잡한 로직을 적용할 수 있습니다.

 

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

    @Mapping(target = "fullName", expression = "java(user.getFirstName() + \" \" + user.getLastName())")
    UserDTO toUserDTO(User user);
}

 

 

d. 커스텀 메서드 (Custom Methods):

매핑 클래스 내에 커스텀 변환 메서드를 정의하여 재사용할 수 있습니다.

 

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

    UserDTO toUserDTO(User user);

    default String mapRoleToString(Role role) {
        return role != null ? role.name() : null;
    }

    @Mapping(source = "role", target = "role", qualifiedByName = "mapRoleToString")
    UserDTO toUserDTOSpecific(User user);
}

 

 

6. 전체적인 흐름 요약

 

  1. 엔티티와 DTO 정의:

    • Todo 엔티티와 TodoResponseDTO DTO를 정의.
  2. Mapper 인터페이스 작성:

    • @Mapper 어노테이션을 사용하여 Mapper 인터페이스 생성.
    • @Mapping 어노테이션을 사용하여 복잡한 매핑 규칙 정의.
  3. MapStruct가 매핑 구현 생성:

    • 컴파일 시점에 MapStruct가 매핑 구현 클래스를 자동으로 생성.
  4. 서비스 및 컨트롤러에서 Mapper 사용:

    • @Autowired 또는 생성자 주입을 통해 Mapper를 주입받아 사용.
    • 엔티티를 DTO로 변환하거나 그 반대로 변환.

 

 

 

 

 

 

componentModel의 주요 옵션

 

@Mapper(componentModel = "spring") 어노테이션은 MapStruct를 사용할 때 매퍼(Mapping) 인터페이스가 어떤

**컴포넌트 모델(Component Model)**을 따를지를 지정하는 중요한 설정입니다. componentModel 속성은 매퍼가 생성된 후 어떻게 관리되고 주입되는지를 결정합니다.

 

componentModel의 주요 옵션

MapStruct는 여러 가지 컴포넌트 모델을 지원하며, 각 모델은 특정 DI(Dependency Injection) 프레임워크와의 통합 방식을 정의합니다. 다음은 componentModel에서 사용할 수 있는 주요 옵션들입니다:

  1. default
  2. spring
  3. jsr330
  4. cdi

 

 

1. default

  • 설명: 특별한 DI 프레임워크와 통합하지 않는 기본 컴포넌트 모델입니다. 매퍼 구현체는 일반 Java 객체로 생성됩니다.
  • 특징:
    • 매퍼 구현체는 별도의 관리 없이 생성됩니다.
    • 의존성 주입을 지원하지 않으므로, 수동으로 매퍼 인스턴스를 생성하고 사용해야 합니다.

 

@Mapper
public interface UserMapper {
    UserDTO toUserDTO(User user);
}

 

  • 장단점:
    • 장점: 간단하고, 별도의 DI 프레임워크에 의존하지 않음.
    • 단점: DI를 통한 매퍼 주입이 불가능하며, 매퍼 인스턴스를 직접 관리해야 함.

 

 

 

 

2. spring

  • 설명: Spring Framework와 통합되는 컴포넌트 모델입니다. 매퍼 구현체가 Spring Bean으로 등록됩니다.
  • 특징:
    • @Component로 매퍼가 자동 등록됩니다.
    • Spring의 의존성 주입(@Autowired 또는 생성자 주입)을 통해 매퍼를 쉽게 주입받아 사용할 수 있습니다.
  • 사용 예시
@Mapper(componentModel = "spring")
public interface UserMapper {
    UserDTO toUserDTO(User user);
}

 

장단점:

  • 장점: Spring의 DI를 활용할 수 있어 매퍼 사용이 간편함.
  • 단점: Spring Framework에 종속적임.

 

 

3. jsr330

  • 설명: JSR 330 표준(Dependency Injection for Java)을 따르는 컴포넌트 모델입니다. @Inject 어노테이션을 사용하여 매퍼를 주입받을 수 있습니다.
  • 특징:
    • @Named 또는 @Singleton과 같은 JSR 330 어노테이션과 함께 사용됩니다.
    • 다양한 DI 프레임워크와 호환됩니다 (예: Spring, CDI).
  •  

 

@Mapper(componentModel = "jsr330")
public interface UserMapper {
    UserDTO toUserDTO(User user);
}

 

장단점:

  • 장점: JSR 330을 지원하는 다양한 DI 프레임워크와 호환 가능.
  • 단점: 특정 DI 프레임워크에 맞는 추가 설정이 필요할 수 있음.

 

 

4. cdi

  • 설명: **Contexts and Dependency Injection (CDI)**를 지원하는 컴포넌트 모델입니다. 주로 Java EE 또는 Jakarta EE 환경에서 사용됩니다.
  • 특징:
    • CDI의 @Named 어노테이션을 사용하여 매퍼를 관리합니다.
    • Java EE 컨테이너에서 매퍼를 쉽게 주입받아 사용할 수 있습니다.
  •  
@Mapper(componentModel = "cdi")
public interface UserMapper {
    UserDTO toUserDTO(User user);
}

장단점:

  • 장점: Java EE 환경과의 통합이 용이함.
  • 단점: CDI를 지원하지 않는 환경에서는 사용이 제한됨.

 

 

 

 

추가 예시 및 설명

여러 개의 @Mapping 어노테이션 사용하기

MapStruct는 하나의 매핑 메서드에 여러 개의 @Mapping 어노테이션을 사용할 수 있습니다. 이를 통해 복잡한 매핑 규칙을 간편하게 정의할 수 있습니다.

 

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

    @Mapping(source = "user.username", target = "username")
    @Mapping(source = "user.email", target = "email")
    @Mapping(source = "user.nickname", target = "nick")
    TodoResponseDTO toResponseDTO(Todo todo);

    // 반대로 매핑하기
    @Mapping(source = "username", target = "user.username")
    @Mapping(source = "email", target = "user.email")
    @Mapping(source = "nick", target = "user.nickname")
    Todo ofTodo(TodoFromRequestDTO todoFromRequestDTO);
}

 

매핑 순서와 중복 매핑

MapStruct는 각 매핑 규칙을 독립적으로 처리합니다. 동일한 필드에 대해 중복된 매핑을 지정할 경우, 컴파일 오류가 발생할 수 있습니다.

따라서, 매핑 규칙을 명확하게 정의하고 중복되지 않도록 주의해야 합니다.

 

 

 

 

프로젝트 네임과 componentModel 관계

componentModel 설정은 MapStruct의 컴포넌트 모델을 지정하는 옵션으로, 프로젝트 네임과는 무관합니다.

componentModel은 MapStruct에서 제공하는 사전 정의된 옵션 중 하나를 선택해야 하며, 프로젝트의 고유성이나 네임과 관련이 없습니다.

예를 들어, componentModel을 "spring"으로 설정하더라도 프로젝트의 이름이 무엇이든 관계없이 Spring의 DI 컨테이너에 매퍼가 빈으로 등록됩니다.

 

 

 

종합 예시: TodoMapper 인터페이스

 

package net.macaronics.springboot.webapp.mapper;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import net.macaronics.springboot.webapp.dto.todo.TodoResponseDTO;
import net.macaronics.springboot.webapp.dto.todo.TodoFromRequestDTO;
import net.macaronics.springboot.webapp.entity.Todo;

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

    @Mapping(source = "user.username", target = "username")
    @Mapping(source = "user.email", target = "email")
    @Mapping(source = "user.nickname", target = "nick")
    TodoResponseDTO toResponseDTO(Todo todo);

    @Mapping(source = "username", target = "user.username")
    @Mapping(source = "email", target = "user.email")
    @Mapping(source = "nick", target = "user.nickname")
    Todo ofTodo(TodoFromRequestDTO todoFromRequestDTO);
}

 

DTO 클래스 예시

 

package net.macaronics.springboot.webapp.dto.todo;

import java.time.LocalDate;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class TodoResponseDTO {
    private Long id;
    private String username;
    private String email;
    private String nick;
    private String description;
    private LocalDate targetDate;
    private boolean done;
}

@Data
@Builder
public class TodoFromRequestDTO {
    private String username;
    private String email;
    private String nick;
    private String description;
    private LocalDate targetDate;
    private boolean done;
}

 

MapStruct 설정 요약

  1. @Mapper(componentModel = "옵션") 설정:

    • componentModel을 통해 매퍼가 어떤 컴포넌트 모델을 따를지 지정합니다.
    • 지원되는 옵션: default, spring, jsr330, cdi.
  2. 매핑 규칙 정의:

    • @Mapping 어노테이션을 사용하여 소스 필드와 타겟 필드를 매핑합니다.
    • 필요한 만큼 여러 개의 @Mapping을 사용할 수 있습니다.
  3. 매퍼 구현체 생성:

    • MapStruct는 인터페이스 기반으로 매퍼 구현체를 자동 생성합니다.
    • componentModel 옵션에 따라 매퍼가 DI 프레임워크와 통합됩니다.
  4. 매퍼 사용:

    • DI 프레임워크에 따라 매퍼를 주입받아 사용합니다.
    • 예: Spring에서는 @Autowired 또는 생성자 주입을 통해 매퍼를 주입받습니다.

 

 

 

 

 

about author

PHRASE

Level 60  라이트

Books are no better than woods without being opened always. (책은 펴보지 않으면 나무 조각과 같다.)

댓글 ( 0)

댓글 남기기

작성