DTO와 Entity를 서로 변환해주는 작업을 Controller가 직접 하지않고, 그 행위를 Mapper가 하도록 요청하여 역할을 분리한다.
@Component
public class MemberMapper {
// MemberPostDto를 Member로 변환
public Member memberPostDtoToMember(MemberPostDto memberPostDto) {
return new Member(0L,
memberPostDto.getEmail(),
memberPostDto.getName(),
memberPostDto.getPhone());
}
// MemberPatchDto를 Member로 변환
public Member memberPatchDtoToMember(MemberPatchDto memberPatchDto) {
return new Member(memberPatchDto.getMemberId(),
null,
memberPatchDto.getName(),
memberPatchDto.getPhone());
}
// Member를 MemberResponseDto로 변환
public MemberResponseDto memberToMemberResponseDto(Member member) {
return new MemberResponseDto(member.getMemberId(),
member.getEmail(),
member.getName(),
member.getPhone());
}
}
@RestController
@RequestMapping("/members")
@Validated
public class MemberController {
private final MemberService memberService;
private final MemberMapper mapper;
// MemberMapper DI
public MemberController(MemberService memberService, MemberMapper mapper) {
this.memberService = memberService;
this.mapper = mapper;
}
@PostMapping
public ResponseEntity postMember(@Valid @RequestBody MemberPostDto memberDto) {
// 매퍼를 이용해서 MemberPostDto를 Member로 변환
Member member = mapper.memberPostDtoToMember(memberDto);
Member response = memberService.createMember(member);
// 매퍼를 이용해서 Member를 MemberResponseDto로 변환
return new ResponseEntity<>(mapper.memberToMemberResponseDto(response),
HttpStatus.CREATED);
}
}
위 예시를 통해 Controller의 역할이 분리되었지만 여전히 문제점이 남아있다.
만약 엔티티와 컨트롤러가 많아진다면, 그에 따라 수작업으로 작성해아 할 mapper 클래스 코드가 어마무시하게 늘어난다.
이를 해결하기 위해 MapStruct
가 탄생했다.
MapStruct는 Mapper 클래스를 자동으로 구현해주는 코드 자동 생성기이며, 이를 사용함으로써 생산성을 향상시킬 수 있다.
build.gradle
의존 라이브러리 설정dependencies {
...
...
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}
@Mapper(componentModel = "spring")
public interface MemberMapper {
Member memberPostDtoToMember(MemberPostDto memberPostDto);
Member memberPatchDtoToMember(MemberPatchDto memberPatchDto);
MemberResponseDto memberToMemberResponseDto(Member member);
}
@Mapper
애너테이션의 attribute로 componentModel = "spring"
을 지정해주면 스프링 빈으로 등록된다.프로젝트 -> build -> Mapper 인터페이스가 위치한 패키지 내부
import [패키지 경로].MemberMapper;