쉬었음 코리아
취업/잡담Spring에서 DTO란 무엇일까? 엔티티와 DTO를 분리하는 이유
쉬었음 청년
81
0

Spring Boot로 게시판이나 커뮤니티 서비스를 만들다 보면 Entity, DTO, Request, Response 같은 용어를 자주 보게 된다.

처음에는 이 개념들이 꽤 헷갈린다.

특히 JPA를 사용하면 데이터베이스 테이블과 연결되는 엔티티가 있고, API 요청이나 응답에 사용하는 DTO가 따로 등장한다.

처음에는 이런 생각이 들 수 있다.

그냥 엔티티를 그대로 반환하면 안 되나? 왜 굳이 DTO를 따로 만들어야 하지?

이번 글에서는 DTO가 무엇인지, 그리고 Spring 프로젝트에서 엔티티와 DTO를 왜 분리해서 사용하는지 정리해보려고 한다.

DTO란 무엇일까?

DTO는 Data Transfer Object의 줄임말이다.

말 그대로 데이터를 전달하기 위한 객체다.

Spring Boot 프로젝트에서는 보통 클라이언트와 서버 사이에서 데이터를 주고받을 때 DTO를 사용한다.

예를 들어 프론트엔드에서 게시글 등록 요청을 보낼 때는 이런 데이터가 필요하다.

제목 본문 닉네임 비밀번호 카테고리 이미지 정보

반대로 서버가 게시글 목록을 응답할 때는 이런 데이터가 필요할 수 있다.

게시글 ID 제목 작성자 작성일 조회수 댓글 수

이처럼 요청과 응답에 필요한 데이터 형태는 상황마다 다르다.

DTO는 이 데이터를 API 목적에 맞게 담아 전달하는 역할을 한다.

Entity와 DTO는 역할이 다르다

JPA에서 엔티티는 데이터베이스 테이블과 연결되는 객체다.

예를 들어 게시글 엔티티는 게시글 테이블과 연결된다.

@Entity public class PostEntity { @Id private Long id; private String title; private String content; private String nickName; }

이 엔티티는 데이터베이스에 저장되는 구조와 밀접하게 연결되어 있다.

반면 DTO는 데이터베이스 저장 구조보다는 API 요청과 응답에 맞춰진 객체다.

public record PostDto( Long postId, String title, String writer, LocalDateTime createdAt ) { }

즉, 엔티티는 데이터베이스 중심이고 DTO는 API 전달 중심이다.

둘은 비슷해 보일 수 있지만 목적이 다르다.

Entity - 데이터베이스 테이블과 매핑되는 객체 - JPA가 관리하는 객체 - 저장, 수정, 조회의 기준이 됨 DTO - 데이터를 전달하기 위한 객체 - API 요청과 응답에 사용됨 - 필요한 데이터만 선택해서 담을 수 있음 dto.png

이 DTO는 투표 정보를 클라이언트에게 전달하기 위한 객체다.

필드 구성을 보면 투표 응답 화면에서 필요한 데이터만 담고 있다.

pollId - 투표를 구분하기 위한 ID question - 투표 질문 startAt - 투표 시작 시간 endAt - 투표 종료 시간

즉, 투표 엔티티 전체를 그대로 반환하는 것이 아니라, 화면에 필요한 정보만 DTO로 만들어서 응답하는 방식이다.

여기에 실제 코드 캡처 이미지를 넣으면 좋다.

실제 프로젝트에서 사용한 PollDto 코드 예시

왜 엔티티를 그대로 반환하지 않을까?

처음에는 엔티티를 그대로 컨트롤러에서 반환해도 편해 보인다.

@GetMapping("/polls/{id}") public PollEntity getPoll(@PathVariable Long id) { return pollService.findPoll(id); }

하지만 이런 방식은 문제가 생길 수 있다.

가장 큰 문제는 엔티티 안에 API 응답으로 보내면 안 되는 정보가 포함될 수 있다는 점이다.

예를 들어 회원 엔티티라면 비밀번호 해시, 권한, 내부 관리용 값 등이 있을 수 있다.

@Entity public class UserEntity { private Long id; private String userId; private String password; private String role; }

이런 엔티티를 그대로 응답하면 클라이언트에게 굳이 보여줄 필요 없는 정보까지 노출될 위험이 있다.

게시글 엔티티도 마찬가지다.

익명 게시글이라면 삭제 비밀번호 해시가 있을 수 있고, 신고 관련 내부 값이나 연관관계 정보가 있을 수도 있다.

그래서 API 응답에서는 필요한 데이터만 DTO에 담아서 보내는 것이 안전하다.

DTO를 사용하면 응답 구조를 깔끔하게 만들 수 있다

엔티티는 데이터베이스 구조에 맞춰져 있다.

하지만 프론트엔드가 원하는 응답 구조는 데이터베이스 구조와 다를 수 있다.

예를 들어 게시글 엔티티에는 작성자 객체가 연관관계로 들어 있을 수 있다.

@ManyToOne private UserEntity user;

하지만 프론트엔드에서는 전체 회원 객체가 필요한 것이 아니라 작성자 이름만 필요할 수 있다.

이럴 때 DTO를 사용하면 응답을 깔끔하게 만들 수 있다.

public record PostListDto( Long postId, String title, String writer, int commentCount, LocalDateTime createdAt ) { }

응답은 이런 식으로 단순해진다.

{ "postId": 1, "title": "DTO란 무엇일까?", "writer": "익명", "commentCount": 5, "createdAt": "2026-06-08T14:30:00" }

프론트엔드는 필요한 값만 받기 때문에 화면을 만들기 쉬워지고, 백엔드는 내부 엔티티 구조를 숨길 수 있다.

DTO는 요청용과 응답용으로 나눌 수 있다

DTO는 크게 요청 DTO와 응답 DTO로 나눠서 생각하면 이해하기 쉽다.

요청 DTO는 클라이언트가 서버로 데이터를 보낼 때 사용한다.

예를 들어 게시글 작성 요청 DTO는 이런 형태가 될 수 있다.

public class PostRequest { private String title; private String content; private String password; private String nickName; }

반대로 응답 DTO는 서버가 클라이언트에게 데이터를 내려줄 때 사용한다.

public record PostResponse( Long postId, String title, String content, String nickName, LocalDateTime createdAt ) { }

요청과 응답은 목적이 다르다.

게시글 작성 요청에는 비밀번호가 필요할 수 있지만, 게시글 조회 응답에 비밀번호가 포함되면 안 된다.

그래서 요청 DTO와 응답 DTO를 분리하는 것이 좋다.

요청 DTO - 클라이언트가 서버로 보내는 데이터 - 게시글 작성, 회원가입, 로그인 등에 사용 응답 DTO - 서버가 클라이언트로 보내는 데이터 - 게시글 목록, 댓글 목록, 투표 결과 등에 사용Java record를 DTO로 사용하는 이유

최근 Java에서는 DTO를 만들 때 record를 사용하는 경우도 많다.

public record PollDto( Long pollId, String question, LocalDateTime startAt, LocalDateTime endAt ) { }

기존 class로 DTO를 만들면 필드, 생성자, getter를 따로 작성해야 한다.

public class PollDto { private final Long pollId; private final String question; private final LocalDateTime startAt; private final LocalDateTime endAt; public PollDto(Long pollId, String question, LocalDateTime startAt, LocalDateTime endAt) { this.pollId = pollId; this.question = question; this.startAt = startAt; this.endAt = endAt; } public Long getPollId() { return pollId; } public String getQuestion() { return question; } }

하지만 record를 사용하면 이런 반복 코드를 줄일 수 있다.

public record PollDto( Long pollId, String question, LocalDateTime startAt, LocalDateTime endAt ) { }

record는 생성자, 접근자, equals, hashCode, toString 등을 자동으로 만들어준다.

그래서 단순히 데이터를 담아 전달하는 DTO에는 잘 어울린다.

DTO를 사용했을 때의 장점

DTO를 사용하면 여러 장점이 있다.

첫 번째는 보안이다.

엔티티를 그대로 반환하지 않기 때문에 비밀번호, 내부 상태값, 관리용 필드 같은 민감한 정보가 노출되는 것을 막을 수 있다.

두 번째는 API 응답 구조를 안정적으로 유지할 수 있다는 점이다.

엔티티 구조가 바뀌더라도 DTO 구조를 유지하면 프론트엔드가 받는 응답 형태를 크게 흔들지 않을 수 있다.

세 번째는 필요한 데이터만 전달할 수 있다는 점이다.

엔티티 전체를 보내지 않고 화면에 필요한 값만 골라서 응답할 수 있다.

네 번째는 계층 분리가 명확해진다는 점이다.

엔티티는 데이터베이스와 비즈니스 로직에 집중하고, DTO는 API 요청과 응답에 집중한다.

이렇게 역할을 나누면 프로젝트 구조가 더 깔끔해진다.

DTO를 사용할 때 주의할 점

DTO를 무조건 많이 만든다고 좋은 것은 아니다.

너무 작은 기능마다 DTO를 과하게 나누면 파일이 많아지고 관리가 복잡해질 수 있다.

하지만 요청과 응답의 목적이 다르거나, 엔티티에 노출되면 안 되는 필드가 있다면 DTO를 분리하는 것이 좋다.

특히 다음과 같은 경우에는 DTO 사용이 거의 필수에 가깝다.

비밀번호나 내부 관리 필드가 있는 경우 엔티티 연관관계가 복잡한 경우 프론트엔드에 필요한 응답 형태가 엔티티와 다른 경우 요청값 검증이 필요한 경우 API 응답 구조를 안정적으로 유지하고 싶은 경우정리

DTO는 데이터를 전달하기 위한 객체다.

Spring Boot와 JPA 프로젝트에서는 엔티티를 그대로 요청과 응답에 사용하기보다, DTO를 따로 만들어 사용하는 것이 일반적이다.

핵심은 다음과 같다.

Entity - 데이터베이스 테이블과 연결되는 객체 - JPA가 관리하는 객체 - 저장과 변경의 중심 DTO - 데이터를 전달하기 위한 객체 - API 요청과 응답에 사용 - 필요한 데이터만 담을 수 있음

내 프로젝트에서 사용한 PollDto도 같은 목적을 가진다.

public record PollDto( Long pollId, String question, LocalDateTime startAt, LocalDateTime endAt ) { }

이 DTO는 투표 엔티티 전체를 그대로 노출하지 않고, 클라이언트에게 필요한 투표 정보만 전달하기 위해 사용한다.

처음에는 DTO를 따로 만드는 것이 번거롭게 느껴질 수 있다.

하지만 프로젝트가 커질수록 엔티티와 DTO를 분리하는 구조는 유지보수, 보안, 응답 설계 측면에서 큰 도움이 된다.

결국 DTO는 단순한 데이터 객체가 아니라, 서버와 클라이언트 사이에서 어떤 데이터를 주고받을지 정리해주는 API 설계의 중요한 기준이라고 볼 수 있다.

0
0

댓글 0

댓글 불러오는 중...

실시간 인기글