1️⃣ DAO (Data Access Object)
- 실제 DB에 접근하는 객체
DB에서 데이터를 꺼내오거나 넣는 역할
DB에 접속하여 데이터의 CRUD작업을 하는 클래스 - Service와 실제 데이터베이스를 연결하는 역할을 하게 됨
- 데이터베이스에 접근하기 위한 로직과 비즈니스 로직을 분리하기 위해 사용함
(원래 DB의 데이터와 프로그래밍 언어는 패러다임의 불일치로 인해 사용할 수 없음)
Spring Data JPA에서는 JpaRepository를 상속받는 인터페이스가 DAO의 역할을 하게된다.
2️⃣ Entity
이때, Entity Class를 통해 클래스를 DB테이블과 1:1 매칭할 수 있음
- Entity는 실제 DB테이블에 존재하는 Column들과 매핑되는 핵심 클래스
- Entity는 DB의 테이블과 1대1 대응이며, 테이블에 가지지 않는 칼럼을 필드로 가져서는 안됨
- 이를 기준으로 테이블이 생성되고 스키마가 변경됨
- 절대 요청이나 응답값을 전달하는 클래스로 사용해서는 안됨
- Entity는 id로 구분되며, 비지니스 로직을 포함할 수 있음
setter를 가지는 경우 가변 객체로 활용 가능
public class Member {
private final Long id;
private final String email;
private final String password;
private final Integer age;
public Member() {
}
public Member(Long id, String email, String password, Integer age) {
this.id = id;
this.email = email;
this.password = password;
this.age = age;
}
}
💚 Entity, DTO 클래스를 분리하는 이유
Entity 클래스를 통해 DB에서 데이터를 꺼내왔지만, 데이터를 접근해야하는 경우 문제가 생김!!
→ DTO 사용
데이터를 움직일 때 Entity 객체를 그대로 사용하지 않고 DTO를 사용하는 이유는 무엇일까?
- View와 DB의 역할을 분리하기 위해서
- Entity 객체의 변경을 피하기 위하여
- Entity는 실제 DB테이블과 매핑되어 있어 만약 변경될 시에 다른 클래스에 영향을 미침
- DTO는 View와 통신하며 자주 변경되므로
- Entity 클래스를 보호하기 위해 분리해주어야 함
- 도메인 모델링을 지키기 위하여
3️⃣ DTO (Data Transfer Object)
- 데이터를 Transfer(이동)하기 위한 객체
- 계층간 데이터를 주고 받을때, 데이터를 담아 전달하는 바구니임
- 주로 Client와 Controller 사이에서 데이터 주고받을 때 활용
(여러 레이어 사이에서 사용은 가능) - Client가 Controller에 요청을 보낼 때도 RequestDto의 형식으로 데이터가 이동
Controller가 Client에게 응답을 보낼 때도 ResponseDto의 형태로 데이터를 보냄 - DTO는 로직을 갖고 있지 않는 순수한 데이터 객체
일반적으로 getter/setter 메서드만을 가짐 (Setter보다 생성자 쓰는거 권유)
💚 Setter 보다 생성자 사용을 권유하는 이유
setter의 경우 변조 가능성이 있기 때문
//getter와setter 메서드 만을 가진다
public class UserDTO {
private String name;
private String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
아래와 같이 생성자로 값을 넣어주도록 하게 하면 전달하는 과정에서 변조가 불가능
//생성자를 이용한 불변 객체
public class UserDTO {
private String name;
private String id;
public UserDTO(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
4️⃣ VO (Value Object)
- 값 자체를 표현하는 객체
(고유번호가 다른 만원 2장이 있으면 둘다 10000의 값을 가지므로 동일하다고 여김) - getter 메소드와 비지니스 로직을 포함할 수 있으며 setter 메소드는 가지지 않음
- 특정 값 자체를 표현하기 때문에 setter 같은 성격의 변조 가능성이 있는 메서드가 존재하면 안되며 생성자를 사용해야함
- 값 비교를 위해서는 equals()와 hashCood() 메소드를 오버라이딩 해줘야 함
equals()와 hashCood() 메소드를 오버라이딩 하지 않았을 때
// Money.java
public class Money {
private final String currency;
private final int value;
public Money(String currency, int value) {
this.currency = currency;
this.value = value;
}
public String getCurrency() {
return currency;
}
public int getValue() {
return value;
}
}
// MoneyTest.java
public class MoneyTest {
@DisplayName("VO 동등비교를 한다.")
@Test
void isSameObjects() {
Money money1 = new Money("원", 10000);
Money money2 = new Money("원", 10000);
assertThat(money1).isEqualTo(money2);
assertThat(money1).hasSameHashCodeAs(money2);
}
}
equals()와 hashCood() 메소드를 오버라이딩 했을 때
// Money.java
public class Money {
private final String currency;
private final int value;
public Money(String currency, int value) {
this.currency = currency;
this.value = value;
}
public String getCurrency() {
return currency;
}
public int getValue() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Money money = (Money) o;
return value == money.value && Objects.equals(currency, money.currency);
}
@Override
public int hashCode() {
return Objects.hash(currency, value);
}
}
// MoneyTest.java
public class MoneyTest {
@DisplayName("VO 동등비교를 한다.")
@Test
void isSameObjects() {
Money money1 = new Money("원", 10000);
Money money2 = new Money("원", 10000);
assertThat(money1).isEqualTo(money2);
assertThat(money1).hasSameHashCodeAs(money2);
}
}
5️⃣ 총정리 비교
분류 | DTO | VO | ENTITY |
정의 | 레이어간 데이터 전송용 객체 | 값 표현용 객체 | DB 테이블 매핑용 객체 |
상태 변경 여부 | setter 존재 시 가변 setter 비존재 시 불변 |
불변 | setter 존재 시 가변 setter 비존재 시 불변 |
로직 포함 여부 | 포함 불가능 | 포함 가능 | 포함 가능 |
💻 reference
[Spring] 스프링 패키지 구조, DAO, DTO, Entity, Repository 에 대하여, DTO를 사용하는 이유
스프링 패키지 구조 스프링 패키지를 나눌 때 전체적인 그림은 일반적으로 [그림 1]과 같다. 이렇게 계층을 나누어 관리하는 것이 유지 보수하기에 용이하며 디버깅하기도 쉽다. DTO, DAO, Repository
code-lab1.tistory.com
DTO, VO, Entity - 개념 정리 및 차이점
DTO vs VO vs Entity 우리가 Spring Framework를 사용하면서 비슷한 개념이라고 생각했던 DTO, VO, Entity의 개념 및 차이점을 정리한다. 1. DTO (Data Transfer Object) DTO(Data Transfer Object)는 데이터 전송(이동) 객체(Jav
devmoony.tistory.com
DTO vs VO vs Entity
DTO와 VO는 분명히 다른 개념이다. 그런데, 같은 개념으로 생각해서 사용하는 경우가 많다. 왜일까? ⌜Core J2EE Patterns: Best Practices and Design Strategies…
tecoble.techcourse.co.kr
[JAVA] DTO와 VO의 차이
데이터를 위한 객체를 만들다 보면 항상 DTO와 VO를 혼용해서 쓰고 하는데, 어떤 것이 맞는 것인지 항상 헷갈렸다. 한번 정리해보면서 이 둘의 차이는 무엇이고 어떤 상황에서 쓰는 것이 가장 이
maenco.tistory.com
'Server > Spring Boot' 카테고리의 다른 글
[Spring Boot] ERD (Entity Relationship Diagram) 란? (0) | 2023.10.15 |
---|---|
[Spring Boot] JWT를 사용한 인증, 인가 과정 (Access Token, Refresh Token 이용) (0) | 2023.10.01 |
[Spring Boot] 빌더(Builder) 패턴의 정의, 생성자 패턴 빌더 패턴 비교 (0) | 2023.09.25 |
[Spring] 스프링 의존성 주입 종류와 @RequiredArgsConstructor 어노테이션을 사용한 생성자 주입 (0) | 2023.09.24 |
[Chapter 03] 스프링 부트에서 JPA로 데이터베이스 다뤄보자 (1) - 등록 (0) | 2023.09.24 |