ModelMapper와 MapStruct는 하나의 객체의 값을 다른 객체에 바인딩 시킬 때 쓰인다.
보통 Entity로 가져온 데이터를 Response DTO에 바인딩 시킬 때 쓰는 라이브러리다.
아래와 같은 Member Entity의 값을 DTO로 넘기는 예제를 만들어보겠다.
@Entity
@Getter @Setter
public class Member {
@Id @GeneratedValue
@Column
private Long id;
private String name;
}
라이브러리 안쓰고 사용하기
@Getter
public class MemberResponseDto {
private String name
private String author;
public MemberResponseDto(Posts entity) {
this.name = entity.getName();
}
}
아래와 같이 DTO의 생성자를 호출해서 값을 바인딩한다.
Member member = new Member();
member.setName("loose");
MemberResponseDto memberResponseDto = new MemberResponseDto(member);
System.out.println(memResponseDto.getName("loose")); // loose 출력
Model Mapper 라이브러리 사용
gradle에 Model Mapper 라이브러리 추가
implementation 'org.modelmapper:modelmapper:2.4.2'
DTO에 Getter와 Setter를 필수로 넣어준다.
@Getter @Setter //필수
public class MemberResponseDto {
private String name
private String author;
}
아래와 같이 Dto에 바인딩 후 출력한다.
Member member = new Member();
member.setName("loose");
ModelMapper modelMapper = new ModelMapper();
MemberResponseDto memberResponseDto = modelMapper.map(member, MemberResponseDto.class);
System.out.println(memberResponseDto.getName()); //loose 출력
하지만 Model Mapper는 성능상의 이슈로 잘 쓰이지는 않는다고 한다.
MapStruct 라이브러리 사용
gradle에 MapStruct 라이브러리 추가
MapStruct도 Model Mapper처럼 getter와 setter를 필수로 사용한다.
그렇기 때문에 보통 Lombok을 같이 사용한다.
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor "org.mapstruct:mapstruct-processor:1.4.2.Final"
compileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
Mappers.getMapper 사용
Entity 값을 DTO에 바인딩 하기위해서 @Mapper가 붙은 Interface를 필수로 만들어야한다.
@Mapper
public interface SimpleSourceDestinationMapper {
MemberDto sourceToDestination(Member source);
Member destinationToSource(MemberDto destination);
}
만든 Interface를 Mappers.getMapper로 가져와서 아래와 같이 사용할 수 있다.
private SimpleSourceDestinationMapper mapper
= Mappers.getMapper(SimpleSourceDestinationMapper.class);
@Test
public void test() throws Exception {
Member member = new Member();
member.setName("loose");
MemberDto memberDto = mapper.sourceToDestination(member);
System.out.println(memberDto.getName()); // loose 출력
}
의존성 주입 사용
@Mapper에(componentModel = "spring")를 적어주면 위처럼 Mappers.getMapper로 가져오지 않고 의존성 주입을 사용할 수 있다.
@Mapper(componentModel = "spring")
public interface SimpleSourceDestinationMapper {
MemberDto sourceToDestination(Member source);
Member destinationToSource(MemberDto destination);
}
@Autowired
MemberMapper mapper;
@Test
public void test() throws Exception {
Member member = new Member();
member.setName("loose");
MemberDto memberDto = mapper.sourceToDestination(member);
System.out.println(memberDto.getName()); // loose 출력
}
Mappers.getMapper 와 의존성 주입 이용하지 않고 변환하기
아래와 같이 인터페이스를 작성하면 의존성 주입을 하지 않고도 변환이 가능하다.
@Mapper(componentModel = "spring")
public interface MemberMapper {
MemberMapper INSTANCE = Mappers.getMapper(MemberMapper.class);
MemberDto to(Member member);
}
//Mappers.getMapper도 필요없고 의존성 주입도 필요 없다.
@Test
public void test() throws Exception {
Member member = new Member();
member.setName("loose");
MemberDto memberDto = MemberMapper.INSTANCE.to(member);
System.out.println(memberDto.getName()); // loose 출력
}
변환되어야 할 필드가 너무 많을 때 사용하면 좋은 라이브러리인 것은 확실하다.
그렇기에 DTO가 크지 않다면 소규모 프로젝트에서 굳이 쓸 이유가 없을 듯 하다.
'🍃 Spring' 카테고리의 다른 글
스프링부트 로그 찍는 법, 로그 파일 만드는 방법 (0) | 2022.12.01 |
---|---|
@Component와 Static 메소드 중 Utility Class는 어디에 만들까? (0) | 2022.11.13 |
@RequestBody, @ModelAttribute의 사용 이유와 목적, 활용 (0) | 2022.10.23 |
Spring Boot로 만드는 Spring Security 로그인 구현 - JWT(2) (6) | 2022.10.18 |
Spring Boot로 만드는 Spring Security 로그인 구현 - Session(1) (2) | 2022.10.10 |