개발(React | Java)/자바 기초 | 문법

📘 Spring Boot 입문 (4)DTO · Entity · DAO 완전 정리 — 왜 분리해야 하는가?

dev-parrot 2025. 12. 12. 16:34

스프링 프로젝트를 보다 보면
DTO, Entity, DAO라는 용어가 계속 등장합니다.

초보자에게 가장 흔한 실수는
👉 “엔티티를 그대로 API 응답으로 써도 되지 않나요?” 입니다.

결론부터 말하면 절대 안 됩니다.
이번 글에서는 각 개념의 역할과 왜 반드시 분리해야 하는지
실전 예제와 함께 명확하게 설명합니다.


📌 목차

  1. DTO / Entity / DAO 한 줄 요약
  2. Entity란 무엇인가?
  3. DTO란 무엇인가?
  4. DAO(Repository)란 무엇인가?
  5. 왜 Entity를 그대로 쓰면 안 되는가?
  6. 올바른 계층별 흐름
  7. 실전 예제 (회원 조회 API)
  8. 자주 하는 실수
  9. 마무리
  10. 대표 태그

1️⃣ DTO / Entity / DAO 한 줄 요약


구분 역할
Entity DB 테이블과 1:1 매핑되는 객체
DTO 계층 간 데이터 전달용 객체
DAO(Repository) DB 접근 담당

👉 역할이 완전히 다릅니다.


2️⃣ Entity란 무엇인가?

Entity는 데이터베이스 테이블을 Java 객체로 표현한 클래스입니다.
JPA를 사용할 때 @Entity로 표시합니다.

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String email;
    private String password;
}

 

 

✔ DTO의 특징

  • DB와 직접적인 연관 없음
  • 필요한 데이터만 담음
  • 보안에 유리 (비밀번호 제외 가능)
  • API 스펙에 최적화

4️⃣ DAO(Repository)란?

DAO는 DB에 접근하는 역할만 담당하는 계층입니다.
스프링에서는 보통 Repository로 표현합니다.

public interface UserRepository extends JpaRepository<User, Long> {
}

 

✔ DAO의 역할

  • 저장(save)
  • 조회(find)
  • 수정
  • 삭제

👉 비즈니스 로직은 절대 DAO에 있으면 안 됨


5️⃣ 왜 Entity를 그대로 쓰면 안 되는가? (매우 중요)

❌ 잘못된 예:

@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
    return userRepository.findById(id).get();
}

 

🚨 문제점

1️⃣ 보안 문제

  • password, 내부 필드가 그대로 노출됨

2️⃣ API 변경 = DB 구조 변경

  • 필드 하나 추가/삭제 시 API 깨짐

3️⃣ 엔티티 변경 시 사이드 이펙트

  • JPA 영속성 컨텍스트 예기치 않은 업데이트

4️⃣ 레이어 간 결합도 증가

  • 유지보수 지옥 시작

6️⃣ 올바른 계층별 흐름

[Client]
   ↓
Controller (DTO 사용)
   ↓
Service (Entity ↔ DTO 변환)
   ↓
Repository (Entity만 사용)
   ↓
DB

 

👉 Controller는 DTO만 알고
👉 Repository는 Entity만 알도록 분리


7️⃣ 실전 예제 — 회원 조회 API

✔ Entity

@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;

    private String email;
    private String password;
}

 

✔ DTO (응답용)

public class UserResponseDto {
    private Long id;
    private String email;

    public UserResponseDto(User user) {
        this.id = user.getId();
        this.email = user.getEmail();
    }
}

 

✔ Service

@Service
public class UserService {

    private final UserRepository repo;

    public UserService(UserRepository repo) {
        this.repo = repo;
    }

    public UserResponseDto getUser(Long id) {
        User user = repo.findById(id)
                        .orElseThrow();
        return new UserResponseDto(user);
    }
}

 

✔ Controller

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService service;

    public UserController(UserService service) {
        this.service = service;
    }

    @GetMapping("/{id}")
    public UserResponseDto getUser(@PathVariable Long id) {
        return service.getUser(id);
    }
}

 

Entity는 절대 Controller로 나오지 않음


8️⃣ 자주 하는 실수

❌ Entity = DTO 라고 생각함

→ 절대 아님. 목적이 다름

❌ Controller에서 Entity 직접 반환

→ 보안/유지보수 문제 발생

❌ DAO에 비즈니스 로직 작성

→ Service 계층 책임

❌ DTO에 로직 넣기

→ DTO는 데이터 운반용 객체


9️⃣ 마무리

이번 글에서 스프링 실무의 핵심 개념을 정리했습니다.

✔ Entity = DB 전용 객체
✔ DTO = 데이터 전달 객체
✔ DAO(Repository) = DB 접근 계층
✔ Entity와 DTO는 반드시 분리
✔ 유지보수·보안·확장성 모두 개선

이 구조를 지키면 스프링 프로젝트의 70%는 성공이라고 봐도 됩니다.