ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Entity와 DTO를 분리하자!
    프로젝트/게시판 프로젝트 2022. 5. 4. 00:55

    클라이언트에서 정보를 받아오면 Member Entity를 그대로 사용하려고 하였습니다.

    하지만 그렇게 되면 Controller 및 Service에 사용하게 될 로직들이 Entity의 속성 값과 의존관계를 맺게 됩니다.

     

    하지만 Entity는 매우 중요한 객체로 사용범위도 크고 모든 데이터를 갖고 있는 객체이므로 Entity와 서비스가 의존관계를 갖게 하는 것은 유지보수 측면에서나 관리측면에서 매우 부적합합니다.

     

    DTO 객체는 View Layer와 데이터를 주고받을 때 사용합니다.

    Entity 객체는 DB Layer와 데이터를 주고받을 때 사용합니다.

     

    실제로 Controller에서 결괏값으로 여러 테이블을 join 해서 줘야 할 경우가 빈번하기 때문에 Entity 클래스만으로 표현하기 어려운 경우도 많습니다.

     

    따라서 꼭 Entity 클래스와 DTO를 분리해야 한다고 합니다.

    만약에 다음과 같은 일이 벌어지면 어떻게 될까요?

    Service에서 findAllMember()을 통해 api 응답 값을 받고, 이를 받은 List <Member>에서 Entity 내 선언된 "name"을 그대로 사용하여 {name=?} 비교를 통해 특정 이름을 갖는 객체를 찾는다고 가정해 보겠습니다.

     

    이때 Entity의 "name"을 "username"으로 변경하면 Service영역의 코드까지 모두 변경해야 합니다.

     

    DTO와 Entity를 구별하지 않으면 발생하는 일

    - 엔티티가 변경되면 API 스펙이 같이 변하게 됩니다. (위의 예시)

    - 엔티티마다 API 검증을 위한 로직이 들어갑니다. (@NotEmpty, NotNull)

    - 엔티티에 프레젠테이션 계층을 위한 로직이 추가됩니다. (사용자에게 보여주기 위한 로직)

     

    Entity -> DTO 변환작업 하기

    Member Entity

    package anthill.Anthill.domain.member;
    
    import lombok.*;
    
    import javax.persistence.*;
    
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    @Builder
    @Getter
    @Table(name = "member")
    @Entity
    public class Member {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY) //MySQL의 AUTO_INCREMENT를 사용
        @Column(name = "member_id")
        private Long id;
    
        @Column(name = "user_id", nullable = false, unique = true, length = 20)
        private String userId;
    
        @Column(name = "password", nullable = false, length = 255)
        private String password;
    
        @Column(name = "nickname", nullable = false, unique = true, length = 20)
        private String nickName;
    
        @Column(name = "name", nullable = false, length = 40)
        private String name;
    
        @Column(name = "phone_number", nullable = false, unique = true, length = 40)
        private String phoneNumber;
    
        @Embedded
        private Address address;
    }

    DB 관련한 사항들만 존재합니다.

     

    MemberRequestDTO생성 : 입력받기 위해 사용할 DTO

    package anthill.Anthill.dto.member;
    
    import anthill.Anthill.domain.member.Address;
    import anthill.Anthill.domain.member.Member;
    
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.Pattern;
    import javax.validation.constraints.Size;
    
    public class MemberRequestDTO {
        //@NotNull : Null만 허용하지 않음 "", " "허용
        //@NotEmpty : null, "" 허용하지 않음 " "허용
        //@NotBlank : null, ""," "허용하지 않음
        //@Pattern : 지정된 패턴만 입력하게 하여 휴대폰 번호 폼에서 이상한 값들이 요청되는 것을 방지합니다.
    
        @NotBlank(message = "아이디를 입력해주세요.")
        @Size(min=5, max=20, message="아이디는 5자 이상 20자 이하로 입력해주세요.")
        private String userId;
    
        @NotBlank(message = "비밀번호를 입력해주세요.")
        @Size(min=8, message="비밀번호를 8자 이상으로 입력해주세요.")
        private String password;
    
        @NotBlank(message = "별명을 입력해주세요.")
        @Size(max=20, message="별명을 20자 이하로 입력해주세요.")
        private String nickName;
    
        @NotBlank(message = "이름을 입력해주세요.")
        private String name;
    
        @NotBlank(message = "휴대전화번호를 입력해주세요.")
        @Pattern(regexp = "(01[016789])(\\d{3,4})(\\d{4})", message = "올바른 휴대폰 번호를 입력해주세요.")
        private String phoneNumber;
    
        Address address;
    
        public Member toEntity(){
            return Member.builder().userId(userId).password(password).nickName(nickName).name(name).phoneNumber(phoneNumber).address(address).build();
        }
    
    
    
    }

    회원가입을 위한 requestDTO입니다.

    컨트롤러로부터 클라이언트에게 요청을 받아서 해당 데이터를 검증할 수 있습니다.

    또한 데이터를 검증한 후에 저장하기 전에는 toEntity() 메서드를 사용하여 엔티티로 변환하여 DB에 저장합니다.

     

    validation을 사용하기 위해 build.gradle에 다음 의존성 추가해야 합니다.

    implementation 'org.springframework.boot:spring-boot-starter-validation'

     

    실제로 DB에 저장할 때 toEntity() 메서드를 호출하는 예시입니다.

    int result = memberService.join(memberRequestDTO.toEntity());

     

     

    출처

    https://ws-pace.tistory.com/72?category=964036 

     

    spring boot REST API Web 프로젝트 (6) - Entity와 DTO의 분리 (Controller 수정)

    스프링 부트 REST API WEB 프로젝트 깃헙 링크 https://github.com/choiwoonsik/springboot_RestApi_App_Project/tree/main/restApiSpringBootApp 수행 목록 환경구성 및 helloworld 출력 H2 DB 연동 Swagger API..

    ws-pace.tistory.com

     

    댓글

Designed by Tistory.