🥛 엔티티 객체를 영속 계층 바깥쪽에서 사용하는 방식 보다는 DTO(Data Transfer Object)를 이용하는 방식을 권장한다.
DTO는 엔티티 객체와 달리 각 계층끼리 주고받는 우편물이나 상자의 개념이다.
순수하게 데이터를 담고 있다는 점에서는 엔티티 객체와 유사하나, 목적 자체가 데이터의 전달로 읽고, 쓰는 것이 모두 허용되는 점이 가능하며 일회성으로 사용되는 성격이 강하다.
JPA를 이용하게 되면 엔티티 객체는 단순히 데이터를 담는 객체가 아니라 실제 데이터베이스와 관련이 있고, 내부적으로 엔티티 매니저(entity manager)가 관리하는 객체이다.
DTO가 일회성으로 데이터를 주고받는 용도로 사용되는 것과 달리 생명주기(life cycle)도 전혀 다르기 때문에 분리해서 처리하는 것을 권장한다.
☞ 웹 에플리케이션을 제작할 때는 HttpServletRequest나 HttpServletResponse를 서비스 계층으로 전달하지 않는 것을 원칙으로 한다. 유사하게 엔티티 객체가 JPA에서 사용하는 객체이므로 JPA 외에서 사용하지 않는 것을 권장한다.
서비스 계층을 생성하고 서비스 계층에서는 DTO로 파라미터와 리턴 타입을 처리하도록 구성한다.
DTO를 사용하면 엔티티 객체의 범위를 한정 지을 수 있기 때문에 좀 더 안전한 코드를 작성할 수 있다.
화면과 데이터를 분리하려는 취지에도 좀 더 부합하다!
DTO의 가장 큰 단점은 Entity와 유사한 코드를 중복으로 개발한다는 점과, 엔티티 객체를 DTO로 변환하거나 반대로 DTO 객체를 엔티티로 변환하는 과정이 필요하다는 것이다.
GuestbookDTO 클래스
package com.example.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GuestbookDTO {
private Long gno;
private String title;
private String content;
private String writer;
private LocalDateTime regDate, modDate;
}
package com.example.demo.service;
import com.example.demo.Entity.Guestbook;
import com.example.demo.dto.GuestbookDTO;
public interface GuestbookService {
Long register(GuestbookDTO dto);
}
package com.example.demo.service;
import com.example.demo.dto.GuestbookDTO;
@Service
public class GuestbookServiceImpl implements GuestbookService{
@Override
public Long register(GuestbookDTO dto) {
return null;
}
}
서비스 계층에서는 파라미터를 DTO타입으로 받기 때문에 이를 JPA로 처리하기 위해서 는 엔티티 타입의 객체로 변환해야 하는 작업이 반드시 필요하다.
이 기능은 DTO클래스에 직접 적용하거나 ModelMapper 라이브러리 혹은 MapStruct 등을 이용해서 처리하기도 하나 여기서는 직접 처리한다.
(기존에 만든 DTO와 엔티티 클래스를 가능하면 변경하고 싶지 않기 때문에
서비스 인터페이스에 default 메서드를 이용해 처리하도록 한다.)