DTO의 필요성을 알기 위해서 가볍게 예시를 들어보겠습니다.
먼저 유저의 회원가입 , 로그인 API설계를 간단하게 해보면 이렇게 될 것 같습니다.
| Method (행위) | POST |
|---|---|
| URI | /login |
| Key | Value |
|---|---|
| id | 회원 id |
| password | 1234 |
| Key | Value |
|---|---|
| status | 201 |
| name | 사용자 이름 |
| Method (행위) | POST |
|---|---|
| URI | /signup |
| Key | Value |
|---|---|
| nickname | 회원 이름 |
| id | 회원 id |
| password | 1234 |
| Key | Value |
|---|---|
| status | 201 |
대충 이렇게 나올 것 같습니다.
이러한 정보를 저장할 User 클래스를 정의할 수 있습니다.
여기서 질문 , 로그인 한 후 클라이언트에게는 사용자의 이름 정도만 전달되면 되는데 User객체를 사용하는 것이 옳바른 사용일까?
이러한 문제를 해결하기 위해 DTO를 사용합니다.
- DTO(Data Transfer Object)란 계층간 데이터 교환을 위해 사용하는 객체(Java Beans)이다.
- 데이터 전송용 객체이면서 엔티티의 사본!!
Client → Controller → Service → Repository → DB
DB → Repository → Service → Controller → Client

이 그림을 보면 알 수 있듯이
- 클라이언트로부터 요청을 받을 때 하나의 객체가 아닌 특정 기능을 수행하는 DTO가 요청을 받고
- Controller -> Service로 이동 후 서비스 단에서 연산을 처리한다.
- 이후 연산이 완료되면 원래 Entity로 바꾸고
- Repository로 이동해서 원래 Entity를 저장하게 한다.
- 돌아오는 과정에서도 Service단에서 다시 응답 DTO가 원하는 결과로 연산을 처리한다.
6.이후 최종적으로 클라이언트에 전달하게 된다.
✅ 굳이 이 객체를 나눠야할까?
어떤 장점이 있나요?
- 하나의 객체로 만들면 개발자는 아주 편하지만
- 사용자 입장에서는 좋지 않습니다.
- 회원가입의 경우 응답으로 이름만 받아도 되는데 id , pw또한 같이 이동하기 때문에 보안적으로 매우 좋지 않습니다.
어떤 단점이 있나요?
- 스프링 3계층(C/S/R) 간의 전송(이동 시) 데이터 변환 위험이 있습니다.
- 즉 원본은 그래도 두고 사본을 두는게 좋지 않을까? setter가 있으면 그 데이터가 클라이언트, 레포에서 왔다가 믿을 수 있을까?
- 사본으로 돌아다니는 친구가 DTO입니다.
- 보안 , 객체의 필드값을 이용한 어떠한 연산을 반환해야할경우 , 기존 객체 만으로는 힘들 수 있다.
- 클라이언트에게 굳이~ 전달되지 않아도 되는 데이터 포함
- 네트워크 비용만 올라가고 , 보안도 안 좋고..
- 클라이언트가 필요한 데이터 미포함
- ex) 구현 코드 연관관계 x → 화면에는 같이 뿌려져야 하는
- ex) 생년월일 저장 → 나이 출력(연산이 필요한 데이터)
- 유지보수성이 올라감(DB 스키마가 변환되었을 때 서버 측만 바꿔도 됨)
- 만약 하나의 객체로 관리되고 있고 db에 컬럼이 바뀌는 상황이라면 클라이언트도 그 컬럼에 접근할 때 코드를 바꿔야한다. 하지만 중간에 관리하는 객체가 있다면 해결이된다.