새소식

Springboot

[Spring] Entity와 DTO는 왜 나눠야 할까?

  • -

오늘은 Entity와 DTO를 분리해야하는 이유와 분리하는 방버에 대해 알아보도록 하겠습니다

처음엔 DTO라는 개념이 처음이라 많이 어려웠었습니다 spring boot를 처음 시작하는 분들이 좀 더 효율적인 프로젝트 구조로 코드를 작성했으면 하는 마음에 이 글을 작성했습니다!

 

먼저 Entity와  DTO를 분리하는 이유에 대해 알아보기 전

Entity는 뭐고 DTO는 무엇일까요?

Entity란

💡실제 DB 테이블과 매핑되는 핵심 클래스

DTO(Data Transfer Object)

💡 각 계층 간 데이터 교환이 이루어질 수 있도록 하는 객체

즉, 쉽게 표현하면 각 계층 끼리 주고 받는 우편물이나 상자의 개념입니다


Entity와 DTO를 분리하는 이유

  1. Entity는 요청이나 응답 값을 전달하는 클래스로 사용하는 것은 좋지 않습니다
    - 영속성의 목적으로 사용되는 객체이기 때문입니다
    -  Entity를 노출하는 것은 테이블 설계를 공개하는 것과 다름없기에 보안상으로 바람직하지 않은 구조입니다
  2. Entity에서는 setter메서드를 사용을 지양해야합니다
    - Entity에 sett메서드를 사용하게 되면 변경되지 않는 인스턴스에 대해서도 setter로 접근이 가능해지기 때문에
    객체의 일관성과 안전성을 보장하기 힘들어집니다
    - 이러한 이유로 Entity에서는 setter대신 Constructor(생성자) 혹은 Builder를 사용합니다
  3. DTO 는 일회성으로 사용되는 성격이 강합니다
    - 순수하게 데이터를 담고 있다는 점에서 Entity 객체와 유사하지만 목적 자체가 전달이므로 일고 쓰는 것이 모두 가능합니다
  4. 화면별로 필요한 데이터를 선별하여 사용할 수 있습니다
    - 예를 들어 로그인을 할 땐 이메일과 비밀번호만 있으면 됩니다 하지만 dto를 나누지 않고 entity를 이용한다면 필요이상의 속성들까지 데이터 전송에 참여하게 되면서 보안에도 안좋고 속도도 느려지기 때문입니다


이제 Entity와 DTO를 분리해야하는 이유도 알게되었으니
코드 예시로 배운 내용을 알아보겠습니다 

 

Entity와 DTO 분리 전 코드

처음엔 Entity와 DTO를 분리하지 않고

이렇게 엔티티에 getter와 setter를 설정하고 entity와 Controller가 직접적으로 데이터를 전송하도록 코드를 작성했습니다

@Entity
public class User {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="id")
    private int userId;

    @Column(nullable = false)
    private String userName;

    @Column(nullable = false)
    private String userEmail;

    @Column(nullable = false)
    private String userPassword;

    @Column(nullable = false)
    private String userAddress;

    public User() {
    }

    public User(String userName, String userEmail, String userPassword, String userAddress) {
        this.userName = userName;
        this.userEmail = userEmail;
        this.userPassword = userPassword;
        this.userAddress = userAddress;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }
}

 

Entity와 DTO 분리 코드

이렇게 Entity에는 속성만 정의해주고 builder로 빌드 해주었습니다

@Entity
@Getter
public class User {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="id")
    private Long userId;

    @Column
    private String userName;

    @Column(nullable = false)
    private String userEmail;

    @Column(nullable = false)
    private String userPassword;

    @Column
    private String userAddress;

    public User() {
    }

    @Builder
    public User(String userName, String userEmail, String userPassword, String userAddress) {
        this.userName = userName;
        this.userEmail = userEmail;
        this.userPassword = userPassword;
        this.userAddress = userAddress;
    }
}

 

그리고 이렇게 기능별로 필요한 속성들로 DTO를 구성하여 

@AllArgsConstructor
@NoArgsConstructor
@Getter
public class LoginUserRequest {
    private String userEmail;
    private String userPassword;

    public User toEntity(){
        return User.builder()
                .userEmail(userEmail)
                .userPassword(userPassword)
                .build();
    }
}

 

entity가 아닌 DTO를 통해 데이터를 전송해주었습니다

@Service
public class UserService {

    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository){
        this.userRepository=userRepository;
    }
    
    //로그인 
    public User login(LoginUserRequest dto) {
        User loggedUser = userRepository.findByUserEmail(dto.getUserEmail());
        if (loggedUser != null && isPasswordValid(dto.getUserPassword(), loggedUser.getUserPassword()))
            	return loggedUser;
       	   return null;
	}
}

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.