DTO == Data Transfer Object.
dto는 데이터를 전송하기 위해 만든 객체다.
dto를 사용하면 api나 서버 같은 두 시스템 간의 통신을 원활하게 할 수 있다.
민감한 정보가 노출될 가능성도 최소화할 수 있다.
많은 oop 환경에서 dto를 사용한다.
나는 최근 완전 제로베이스에서 스프링부트를 실습하며 학습하고 있다.
dto나 entity도 이때 처음 보았는데 둘이 분명 유사한 기능을 하는 것 같은데
왜 둘이 분리되어 있는지 궁금했다.
어쩔 땐 같이 쓰고 어쩔 땐 한 쪽만 쓰는 이유도 궁금했다.
그런데에는 다 이유가 있었으니...
일단,
oop는 호출(calls)이라는 시스템에 의존한다.
각 호출은 데이터 조회와 약간 비슷하고 시간과 처리 속도를 모두 필요로 한다.
이 과정에서 조심하지 않으면 호출 시 숨기려는 민감한 데이터가 노출될 수가 있다.
예를 들어,
사원 객체의 props 중에
직원 주소, 계좌 번호, 주민등록번호, 비즈니스 로그인 정보가 있다고 치자.
이 사람이 다른 사업장으로 전근을 가려고 한다.
그럴 때, 위 props를 모두 이관할 필요는 없다.
어떤 건 넘기고 어떤 건 넘기지 않는다.
dto를 사용하면 필요한 정보만을 전송할 수 있어 이럴 때 필요하다.
주의
dto는 비즈니스 로직이 아닌 데이터만을 포함해야 한다.
보일러플레이터 코드를 최소화해야 한다.
매번 새로 작성한다 생각하면 좋다.
생성이 쉬워야 한다.
dto가 작성하기 어려울 정도로 복잡하면 망가지기 쉽다.
가독성이 좋아야 한다.
누구 봐도 해석되어야 한다.
그럼 이제 entity를 알아보자.
그런데 2023년 현재 많은 사람들이 사용하는 jpa entity에 대해 기술하기 전에
개인적으로 기록해 둘 것이 있다.
나는 지금 개인적인 이유로 마이바티스를 쓰고 있기 때문이다...
entity는 보통 jpa에서 쓴다.
마이바티스를 사용하면 entity 클래스 안 써도 된다.
그러나 나는 dto를 사용하지 않고 entity 클래스를 생성했으며 그걸로 crud까지 완성했다.
뭐.. 이런 건 사실 다 전적으로 개발자의 선택에 달려 있다 생각한다.
어쨌거나 마이바티스를 쓰면 entity 대신에 dto나 pojo 클래스를 만들고 이를 인터페이스의 메서드 반환 타입이나 파라미터로 쓰는 게 일반적인 거 같다.
내 개인적 상황에 대한 기록은 여기서 마치고 entity 설명으로 넘어간다.
entity는 db에 저장된 테이블을 나타낸다.
entitiy의 각 인스턴스는 테이블 내의 한 행이다.
아래에서 더 자세히 알아보자.
최종적으로, 학생 인스턴스를 만들고 싶다.
그러려면 학생 pojo를 db에 저장해야 한다.
클래스를 만들자.
public class Student {
// 필드, 게터 및 세터
}
여기까지 하면 jpa가 해당 클래스를 인식을 못 한다.
위에 @Entity 달아주자.
@Entity
public class Student {
// 필드, 게터 및 세터
}
그리고 entity 이름은 클래스 이름으로 주면 된다(보통 기본값).
name 속성 사용하면 된다.
@Entity(name="student")
public class Student {
// 필드, 게터 및 세터
}
주의
다양한 jpa 구현체가 기능을 제공하기 위해 entity를 하위 클래스로 만들기 때문에 entity 클래스는 final로 선언되어서는 안 된다.
이제는 entity의 기본 생성자와 기본 키(pk)를 지정하는 것에 대해 알아보자.
각 jpa entity는 고유하게 식별하는 pk를 가져야 한다.
이건 @Id를 달아서 해결한다.
@GeneratedValue달면 더 다양하게 식별자를 생성할 수 있다.
@Entity
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
// 게터 및 세터
}
이렇게 하면 id를 다는데 jpa 제공자가 알잘딱깔센 자동으로 식별자를 선정한다.
이 외에도
@Table, @Column, @Transient, @Temporal, @Enumerated를 가지고
entity와 db를 조물조물 잘 버무려 쓸 수 있다.
이런 거 한 번에 본다고 바로 쓸 수 있게 되는 거 아니니
눈과 머리에 발라만 두자.
자세한 내용은 아래에서...
https://www.baeldung.com/jpa-entities
그럼 dto는 어떻게 쓸 건데?
내가 생각했을 때...
entity만 쓴다면 거르는 거 없이 db랑 데이터 주고 받는 형태일 거 같고
dto만 쓴다면 무언가 필터링 하고 싶을 때일 거 같고
둘 다 쓴다면
특정 내용을 필터링하면서 db와 웹 레이어 간의 데이터 전송을 관리하거나
entity의 내부 데이터를 외부로 노출하지 않으면서 데이터를 조작하고자 할 때 일 거 같다(그 말이 그 말이네).
둘 다 같이 쓰는 경우를 상황과 코드로 한 번 보자.
상황: 학생 정보를 나타내는 entity와 해당 정보를 전달하기 위한 dto가 있다.
@Entity
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
private String studentNumber;
private String major;
// 게터 및 세터
}
public class StudentDTO {
private String name;
private String studentNumber;
// 생성자, 게터 및 세터
}
여기서 entity는 db와의 상호작용을 처리한다.
실제 데이터를 저장하고 관리한다.
dto는 웹 레이어에서 entity의 일부 데이터를 전달하거나 특정 목적에 맞게 변환하기 위해 사용된다.
예를 들어, 학생 목록을 웹 페이지로 보여 준다면
아래와 같이 entity의 일부 데이터가 dto로 변환되어 전송될 수 있다.
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepository;
public List<StudentDTO> getAllStudents() {
List<Student> studentEntities = studentRepository.findAll();
List<StudentDTO> studentDTOs = new ArrayList<>();
for (Student studentEntity : studentEntities) {
StudentDTO studentDTO = new StudentDTO();
studentDTO.setName(studentEntity.getName());
studentDTO.setStudentNumber(studentEntity.getStudentNumber());
studentDTOs.add(studentDTO);
}
return studentDTOs;
}
}
이렇게 하면
entity의 내부 구조와 db 스키마를 외부에 노출하지 않으면서도 데이터를 제어하고 전달할 수 있다.
노출하지 않아도 되는 부분이 있으면 최대한 감추고
중복되는 부분이 있으면 최대한 병합할 것이다.
이 부분은 코딩을 계속 해 나가야 좀 더 정확하게 판단이 될 것 같다.
코딩하면서 설계 바꾸면 안 된다는 거 알고 있지만
이런 프로젝트는 처음이라 어쩔 수 없는 부분이 있다.