실제로 컨트롤러나 서비스 계층 사이에서나, 컨트롤러와 프론트엔드 사이의 데이터 전송은 엔티티를 직접 사용하는 방식이 아닌 DTO를 통해 이루어집니다. 앞선 글에서 언급했듯이 엔티티는 직접적인 수정을 다루기엔 위험하기 때문에, DTO를 통해 Getter/Setter처리를 합니다.
GuestbookDTO
package org.zerock.guestbook.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class GuestbookDTO {
private Long gno;
private String title;
private String content;
private String writer;
private LocalDateTime regDate, modDate;
}
위와 같이 GuestbookDTO를 생성합니다.
그리고 서비스 계층도 생성합니다.
GuestbookService
package org.zerock.guestbook.service;
import org.zerock.guestbook.dto.GuestbookDTO;
public interface GuestbookService {
Long register(GuestbookDTO dto);
}
GuestbookServiceImpl
package org.zerock.guestbook.service;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.zerock.guestbook.dto.GuestbookDTO;
@Service
@Log4j2
public class GuestbookServiceImpl implements GuestbookService{
@Override
public Long register(GuestbookDTO dto) {
return null;
}
}
다음으로는 DTO를 엔티티로 변환하는 작업이 필요합니다. 이 과정은 ModelMapper나 MapStruct와 같은 라이브러리를 이용한다면 자동생성되는 매퍼 클래스를 이용할 수도 있지만 이 책에서는 직접 변환하는 방식을 채택하였습니다.
public interface GuestbookService {
Long register(GuestbookDTO dto);
//아래 매퍼(dto->entity) 메서드 추가
default Guestbook dtoToEntity(GuestbookDTO dto) {
Guestbook entity = Guestbook.builder()
.gno(dto.getGno())
.title(dto.getTitle())
.content(dto.getContent())
.writer(dto.getWriter())
.build();
return entity;
}
}
인터페이스 레벨에서 구현해놓았기 때문에 default 메서드
를 사용합니다.
이제 이를 서비스 구현체에 적용해보겠습니다.
@Service
@Log4j2
public class GuestbookServiceImpl implements GuestbookService{
@Override
public Long register(GuestbookDTO dto) {
log.info("DTO--------------------");
log.info(dto);
Guestbook entity = dtoToEntity(dto);
log.info(entity);
return null;
}
}
일단 서비스에서 dto를 entity로 변환해주는 작업을 했는데, 이것이 정상 동작하는지 테스트를 통해 확인해보겠습니다.
GuestbookServiceTests
package org.zerock.guestbook.service;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.zerock.guestbook.dto.GuestbookDTO;
@SpringBootTest
public class GuestbookServiceTests {
@Autowired
private GuestbookService service;
@Test
public void testRegister() {
GuestbookDTO guestbookDTO = GuestbookDTO.builder()
.title("Sample title.....")
.content("Sample content.....")
.writer("user0")
.build();
System.out.println(service.register(guestbookDTO));
}
}
다음으로는 Service에서 Repository로 Entity를 넘겨 저장하도록 ServiceImpl을 수정하겠습니다.
@Service
@Log4j2
@RequiredArgsConstructor //추가
public class GuestbookServiceImpl implements GuestbookService{
//추가
private final GuestbookRepository repository;
@Override
public Long register(GuestbookDTO dto) {
log.info("DTO--------------------");
log.info(dto);
Guestbook entity = dtoToEntity(dto);
log.info(entity);
//추가
repository.save(entity);
return entity.getGno();
}
}
스프링 빈에 등록되어있는 GuestbookRepository
를 @RequiredArgsConstructor
를 통해 의존성 주입을 하였습니다. 이는 final로 정의된 repository에 대해 자동으로 생성자를 만들어 초기화해주는 어노테이션입니다.
다시한번 테스트 코드를 실행해보면 아래와 같이 데이터베이스에 저장되고, gno값인 301을 반환한 것을 확인할 수 있습니다.