
ํ ํ๋ก์ ํธ์์ ๋งค๋ฒ DTO ๋งคํ์ ์๋์ผ๋ก ํ๋ค ๋ณด๋ ํผ๋ก๊ฐ์ด ์์์ต๋๋ค.
๊ทธ๋์ ๋์
ํ MapStruct! ์ด ๊ธ์์๋ ๊ทธ ๊ฐ๋
๋ถํฐ ์ค์ ์ฝ๋๊น์ง ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
MapStruct๋ก ๋น ๋ฅด๊ณ ๊น๋ํ๊ฒ ๋งคํ ์๋ํํ๊ธฐ!
MapStruct๋ Java Bean ๊ฐ์ ๋งคํ ์ฝ๋๋ฅผ ์ปดํ์ผ ํ์์ ์๋ ์์ฑํด์ฃผ๋ ๊ฐ์ฒด ๋งคํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์
๋๋ค.
Lombok์ฒ๋ผ Annotation ๊ธฐ๋ฐ์ผ๋ก ์ ์ํ๋ฉด, @Mapper ์ธํฐํ์ด์ค ๊ตฌํ์ฒด๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด์ค๋๋ค.
โ๏ธ ์๋ ๋งคํ์์ ํด๋ฐฉ๋๊ณ , ์ฑ๋ฅ๋ ๋ฐ์ด๋ ๊ฐ์ฒด ๋งคํผ์ ๋๋ค.
| ์ฅ์ | ์ค๋ช |
|---|---|
| โ ํผํฌ๋จผ์ค ์ฐ์ | ์ปดํ์ผ ํ์์ ์ฝ๋๋ฅผ ์์ฑ โ ๋ฐํ์ ์ค๋ฒํค๋ ์์ |
| โ ๋ฐ๋ณต ์ ๊ฑฐ | DTO โ Entity ๊ฐ ๋งคํ ์ฝ๋ ์๋ ์์ฑ |
| โ ์ค๋ฅ ๋ฐฉ์ง | ํ๋ ๋๋ฝ, ํ์ ๋ถ์ผ์น ์ ์ปดํ์ผ ์ค๋ฅ ์ ๋ |
| โ ์ ์ง๋ณด์ ์ฉ์ด | ๋ช ์์ ๋งคํ์ผ๋ก ์ถ์ ๋ฐ ํ ์คํธ ์ฉ์ด |
| ๋จ์ | ๋ณด์ ๋ฐฉ๋ฒ |
|---|---|
| โ ๋ฐํ์ ์ ์ฐ์ฑ ๋ถ์กฑ | ์ปดํ์ผ ํ์ ๊ธฐ๋ฐ์ด๋ผ ๋์ ๋งคํ์ ์ด๋ ค์ |
| โ Lombok๊ณผ์ ๊ถํฉ ์ด์ | ์ผ๋ถ IDE ์ค์ ๋ฐ ๋ฒ์ ์ ๋ฐ๋ผ ์ปดํ์ผ ์์ ์ถฉ๋ ๊ฐ๋ฅ |
| โ ๊ณ ๊ธ ๋ก์ง ์ฒ๋ฆฌ ์ด๋ ค์ | ๋ณต์กํ ๋งคํ์ @AfterMapping, expression ๋ฑ์ ์ง์ ์์ฑํด์ผ ํจ |
์๋๋ ์ค๋ฌด์์ ์ฌ์ฉํ MapStruct ๊ธฐ๋ฐ DTO โ Entity ๋งคํ ์์์ ๋๋ค.
// com.example.demo.member.adapter.in.web
@Mapper(componentModel = "spring")
public interface MemberWebMapper {
Member toDomain(CreateMemberRequest createMemberRequest);
CreateMemberResponse toCreateMemberResponse(Member member);
GetMemberResponse toGetMemberResponse(Member member);
default Member toDomain(String memberId) {
return Member.builder()
.id(memberId)
.build();
}
}
// com.example.demo.member.adapter.out.persistence
@Mapper(componentModel = "spring")
public interface MemberPersistenceMapper {
MemberJpaEntity toJpaEntity(Member member);
Member toDomain(MemberJpaEntity memberJpaEntity);
}
Persistence ์์ญ๊ณผ ์ฌ์ฉ์ useCase์์ญ์ ๋ถ๋ฆฌ ์ดํ MapStruct ์ฌ์ฉ
@DisplayName("Member Domain Unit Test")
public class MemberTest {
private final MemberWebMapper mapper = new MemberWebMapperImpl();
@Test
void ํ์_์ ์_์์ฑ_์์ฒญ์์_๋๋ฉ์ธ_๋ณํ() {
// given
CreateMemberRequest request = new CreateMemberRequest(
"user@example.com",
"QWERasdf1234!",
"ํ๊ธธ๋",
GenderEnum.MALE,
"010-1234-5678",
"์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ ํ
ํค๋๋ก 123"
);
// when
Member member = mapper.toDomain(request);
// then
assertAll(
() -> assertEquals("user@example.com", member.getEmail()),
() -> assertEquals("QWERasdf1234!", member.getPassword()),
() -> assertEquals("ํ๊ธธ๋", member.getName()),
() -> assertEquals(GenderEnum.MALE, member.getGender()),
() -> assertEquals("010-1234-5678", member.getPhoneNumber()),
() -> assertEquals("์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ ํ
ํค๋๋ก 123", member.getAddress())
);
}
}
MapStruct๋ ๋ฐ๋ณต์ ์ธ DTO โ Entity ๋งคํ ์ฝ๋๋ฅผ ์ปดํ์ผ ํ์์ ์๋์ผ๋ก ์์ฑํด์ค์ผ๋ก์จ
๊ฐ๋ฐ์์ ์์ฐ์ฑ์ ๋์ด๊ณ , ์ฝ๋์ ์์ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์์ ์ก์ ์ ์๋ ํ๋ฅญํ ๋๊ตฌ์ ๋๋ค.
ํนํ Spring Boot์ ๊ฒฐํฉํ๋ฉด@Mapper(componentModel = "spring")์ค์ ํ๋๋ก DI๊น์ง ์ฐ๋๋๊ธฐ ๋๋ฌธ์
๋ณต์กํ ๋ณํ ๋ก์ง ์์ด ๊น๋ํ๊ณ ๋ช ํํ ์ฝ๋ ๊ตฌ์กฐ๋ฅผ ์ ์งํ ์ ์์ต๋๋ค.