0_ch4n
기계쟁이\n개발자
0_ch4n
0chn.xxx@gmail.com @0ch._.n
전체 방문자
오늘
어제

공지사항

  • All (282)
    • 🖥 CS (21)
      • 네트워크 (12)
      • 운영체제 (3)
      • 자료구조 (2)
      • Web (4)
    • 🧠 Algorithm (185)
      • [C] BOJ (93)
      • [JAVA] Programmers (91)
    • 📚 Study (69)
      • HTML&CSS (19)
      • MySQL (11)
      • JAVA (22)
      • Servlet&JSP (8)
      • Thymeleaf (2)
      • Spring (5)
      • JPA (2)
    • 📖 Book (1)
    • 📃 Certification (6)
      • 정보처리기사 (6)

인기 글

최근 글

최근 댓글

태그

  • 자바
  • Programmers
  • java
  • til
  • 카카오
  • CSS
  • 프로그래머스
  • 코테
  • 코딩테스트
  • kakao

블로그 메뉴

  • 홈
  • 태그
  • 방명록

티스토리

hELLO · Designed By 정상우.
0_ch4n

기계쟁이\n개발자

[Spring] Entity, DTO, DAO, VO?
📚 Study/Spring

[Spring] Entity, DTO, DAO, VO?

2022. 8. 9. 10:53
반응형

 

✔️ Entity

Entity는 DB의 테이블에 존재하는 Column들을 필드로 가지는 객체를 말합니다.

Entity는 DB의 테이블과 1대1로 대응되기 때문에 테이블이 가지지 않는 Column을 필드로 가져서는 안됩니다.

 

예를 들어 user라는 테이블이 name, email, password 라는 컬럼들을 가지고 있다면

 

@Entity
public class User {
    private String name;
    private String email;
    private String password;
}

 

이에 대응하는 Entity 클래스는 위와 같이 user 테이블의 Column들을 필드로 가져야 합니다.

 

JPA를 사용할 때 Entity 클래스에는 @Entity 어노테이션을 붙여서 Entity임을 명시해줘야 하며 내부의 필드에는 @Column, @Id 어노테이션 등을 사용해야 합니다.

 

또한 Entity를 만들 때 Getter를 만들되 외부에서 최대한 사용하지 않도록 내부에 Domain 로직을 구현해야 하고

Setter는 Entity의 인스턴스 값을 변경시킬 수 있기 때문에 Builder 패턴을 사용하는 것이 가장 좋습니다.

 

@Entity
public class User {
    private String name;
    private String email;
    private String password;
    
    @Builder
    public User(String name, String email, String password) {
        this.name = name;
        this.email = email;
        this.password = password;
    }
}

//사용
User user = new User.builder()
        .name("name")
        .email("abc@gmail.com")
        .password("password")
        .build();

 

✔️ DAO(Data Access Object)

DAO는 데이터베이스의 data에 접근하기 위한 객체로 로직 & 비즈니스 로직을 분리하기 위해 사용합니다.

또한 DAO는 효율적인 커넥션 관리와 보안성을 보장하며 Repository package가 DAO에 해당하고 Persistence Layer입니다.

 

public class UserDAO {
    public void join(UserDTO dto) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "root");
        
        PreparedStatement preparedStatement = connection.prepareStatement("insert into user(name, email, password) value(?,?,?)");

        preparedStatement.setString(1, dto.getName());
        preparedStatement.setString(2, dto.getEmail());
        preparedStatement.setString(3, dto.getPassword());
        preparedStatement.executeUpdate();
        
        preparedStatement.close();      
        connection.close();
    }
}

 

✔️ DTO(Data Transfer Object)

DTO는 계층 간 데이터 교환을 하기 위해 사용하는 객체로 getter, setter만 갖고 로직을 가지지 않는 순수한 데이터 객체입니다.

setter를 사용하는지 안하는지에 따라 불변 객체 또는 가변 객체로 사용할 수 있습니다.

 

public class UserDTO {
    private String name;
    private String email;
    
    public UserDTO(String name, String email) {
        this.name = name;
        this.email = email;
    }
    
    public String getName() {
        return name;
    }
    
    public String getEmail() {
        return age;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
}

 

📌 DTO를 사용하는 이유

  1. Entity를 캡슐화하여 민감한 정보가 외부에 노출되지 않게 하기 위해
  2. Entity의 변경 가능성을 방지하기 위해
  3. 요구사항 변화에 따른 영향을 줄이기 위해
  4. 필요한 데이터만 선택적으로 사용하기 위해

 

📌 DTO의 변환 위치

Repository는 DB Access와 영속성 관리에만 집중해야하므로 Repository까지 DTO를 끌고 가는 것은 맞지 않아 보입니다.

 

Controller에서 메서드 인자로 DTO를 받아오는 점을 감안하면 Controller에서 변환하는게 나아 보이지만

DTO를 Domain 객체로 만들 때 Repository를 통한 조회가 필요한 때가 있습니다.

그렇기에 Service에 DTO <-> Domain 변환 로직을 추가하는 것이 개인적으론 제일 나은 방법이라 생각합니다.

 

이 경우 Controller에서 받은 DTO를 그대로 Service에 넘긴다면 Service가 반대로 Controller에 의존하게 됩니다.

이걸 해결하기 위해 Controller로 받은 DTO를 Service가 필요로 하는 형태로 변환해서 보내주어야 합니다.

 

결론적으로 상황에 맞게끔 Controller나 Service 중 적절한 변환 위치를 정하여 사용하는게 좋을 것 같으며 정답은 없는 것 같습니다.

 

저는 개인적으로 Validation을 위해 어차피 Controller에서 DTO를 받기 때문에 굳이 Service까지 DTO를 끌고 갈 필요 없이

Controller에서 요청 때나 응답 때 변환 해주는 것이 깔끔해보입니다.

 

  • 요청
    • 요청 -> DTO -> Controller -> Domain -> Service -> Repository
  • 응답
    • Repository -> Domain -> Service -> Controller -> DTO -> 응답

 

✔️ VO(Value Object)

VO는 값 오브젝트로써 getter만을 가지므로 불변이며 read-only의 특징을 갖고 비즈니스 로직을 포함할 수 있습니다.

VO 객체는 모든 속성이 같다면 똑같은 객체로 보기 위해 equals와 hashcode를 오버라이딩해야 사용해야 합니다.

 

public class UserVO {
    private final String password;
    
    public String getPassword() {
        return password;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(password);
    }
    
    @Override
    public boolean equals(Object obj) {
        if(this == obj) {
            return true;
        }
        if(obj == null || getClass() != obj.getClass()) {
            return false;
        }
        User user = (User) obj;
        if(password == user.password) {
            return true;
        } else {
            return false;
        }
    }
}

 

📄 Reference

https://velog.io/@dyunge_100/DTO-VO-DAO-Entity%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90

반응형
저작자표시 (새창열림)

'📚 Study > Spring' 카테고리의 다른 글

[Spring] Validation  (0) 2022.08.10
[Spring] JUnit을 통한 TDD  (0) 2022.08.05
[Spring] Spring Security + JWT  (0) 2022.08.01
[Spring] Swagger? Spring REST Docs?  (0) 2022.07.21
    0_ch4n
    0_ch4n
    while(true) { study(); }

    티스토리툴바