ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 3. [TodoList] - dto 설계
    AppCenter/TodoList 2023. 5. 17. 22:41
    반응형

     

    도메인, 서비스, 레포지토리를 설계해보았으니 이번엔 dto를 설계해보자.

     

     

     

    dto 를 써야하는 이유

     

    api 통신시 반환 값으로 엔티티 그대로를 반환하면 되지 왜 dto를 사용할까??

     

    지금은 간단한 TodoList 프로젝트지만 만약 프로젝트가 매우 커져서 User 테이블에 10개 이상의 필드가 들어간다고 가정해보자. 

    사용자 이름과 게시한 글 수를 보여주는 화면을 출력하기 위해 데이터를 요청한 뒤 User 엔티티를 반환할 경우 전체 속성을 조회해 반환하기 때문에 요청한 화면에서는 필요없는 속성까지 넘겨주게 되는것이다.

    이렇게되면 API 응답에서 필요 이상으로 많은 속성을 넘겨주기때문에 속도 또한 느려진다.

     

    이것말고도 dto를 사용했을때 여러가지 장점에 대해 잘 정리된 포스트가 있어 아래 링크를 걸어두겠다.

    https://tecoble.techcourse.co.kr/post/2020-08-31-dto-vs-entity/

     

    요청과 응답으로 엔티티(Entity) 대신 DTO를 사용하자

    tecoble.techcourse.co.kr

     

     

     

    TaskRequestDto

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    @Getter
    @Schema(description = "TodoRequest")
    public class TaskRequestDto {
     
        @Getter
        @Setter
        public static class TaskSaveReqDto {
            @Schema(example = "Todo 제목")
            @NotEmpty
            private String title;
     
            @Schema(example = "Todo 내용")
            private String contents;
            @NotEmpty
            @Schema(example = "Todo 기한")
            private String deadline;
     
            private boolean isCompleted;
     
            public Task changeEntity(TaskSaveReqDto TaskSaveReqDto) {                                
                return Task.builder()
                        .title(TaskSaveReqDto.title)
                        .contents(TaskSaveReqDto.contents)
                        .deadline(parseDatetime(TaskSaveReqDto.deadline))
                        .isCompleted(TaskSaveReqDto.isCompleted)
                        .build();
            }
        }
     
        @Getter
        @Setter
        @AllArgsConstructor
        public static class TaskEditRequestDto {
            private String title;
            private String contents;
            private String deadline;
            private boolean isCompleted;
        }
     
        public static LocalDateTime parseDatetime(String deadline) {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return LocalDate.parse(deadline, dateTimeFormatter).atStartOfDay();
        }
    }
    cs

     

    이전에 Service에서 만들었던 CRUD 중 Read 와 Delete는 모두 컨트롤러에서 id 값만 받아오면 가능하기 때문에 따로 RequestDto를 만들 필요가 없다.

     

    TaskSaveRequestDto, TaskEditRequestDto 는 모두 정적 내부 클래스로 만들어 바깥 클래스에 대한 참조를 막아 메모리 누수를 방지하고, 응집도를 높혔다.

     

    수정 시 TaskEditRequestDto를 받아와 Task 로 변환할 때 String 형식의 deadline을 LocalDateTime 형식으로 변환해줘야한다. 이 때, parseDatetime 메소드는 String 형식으로 받아온 deadline을 LocalDateTime 형식으로 변환해주는 역할을 한다.

     

     

    TaskResponseDto

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    public class TaskResponseDto {
     
        @Getter
        @Setter
        public static class TaskSaveRespDto {
            @Schema(example = "Todo 제목")
            @NotEmpty
            private String title;
     
            @Schema(example = "Todo 내용")
            private String contents;
            @NotEmpty
            @Schema(example = "Todo 기한")
            private String deadline;
     
            private boolean isCompleted;
     
            public TaskSaveRespDto(Task task) {
                this.title = task.getTitle();
                this.contents = task.getContents();
                this.deadline = task.getDeadline().toString();                                                            
                this.isCompleted = task.getIsCompleted();
            }
        }
     
        @Getter
        @Setter
        public static class TaskDeleteRespDto {
            @Schema(example = "Todo 제목")
            @NotEmpty
            private String title;
     
            @Schema(example = "Todo 내용")
            private String contents;
            @NotEmpty
            @Schema(example = "Todo 기한")
            private String deadline;
     
            private boolean isCompleted;
     
            public TaskDeleteRespDto(Task task) {
                this.title = task.getTitle();
                this.contents = task.getContents();
                this.deadline = task.getDeadline().toString();
                this.isCompleted = task.getIsCompleted();
            }
        }
     
        @Getter
        @Setter
        @AllArgsConstructor
        public static class TaskEditRespDto {
            private String title;
            private String contents;
            private String deadline;
            private boolean isCompleted;
     
            public TaskEditRespDto(Task task) {
                this.title = task.getTitle();
                this.contents = task.getContents();
                this.deadline = task.getDeadline().toString();
                this.isCompleted = task.getIsCompleted();
            }
        }
    }
     
    cs

     

    TaskRequestDto 와 마찬가지로 정적 내부 클래스로 구현했다.

     

    TaskRequestDto 로 받아온 정보를 Task로 변환해 데이터베이스에 저장한 뒤 TaskResponseDto로 변환하기 위해 Task 를 파라미터로 받는 생성자를 만들었다.

     

     

    UserRequestDto & UserResponseDto

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Getter
    public class UserRequestDto {
     
        @Getter
        @Setter
        public static class UserJoinReqDto {
            private String name;
            private String password;
            private String email;
     
            public User changeEntity(UserJoinReqDto UserJoinReqDto) {                                        
                return User.builder()
                        .name(UserJoinReqDto.name)
                        .password(UserJoinReqDto.password)
                        .email(UserJoinReqDto.email)
                        .build();
            }
        }
    }
    cs

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class UserResponseDto {
     
        @Getter
        @Setter
        public static class UserJoinRespDto {
            private String name;
            private String password;
            private String email;
     
            public UserJoinRespDto(User user) {                                                    
                this.name = user.getName();
                this.password = user.getPassword();
                this.email = user.getEmail();
            }
        }
    }
    cs

     

     

    위에서 dto 에 대해 자세히 설명했기때문에 따로 설명할것이 없다.

     

    domain, dto, service, repository를 분석했으니 다음 포스팅때는 controller에 대해 알아보자.

    728x90
    반응형

    댓글

Designed by Tistory.