본문 바로가기
Engineering WIKI/Spring

[Spring] DTO를 Inner Class로 사용

by wonos 2021. 4. 26.
  • Api별로 화면에 return하는 데이터가 달라 많은 DTO 파일을 생성하게됩니다.
  • Entity들의 데이터를 가공하여 DTO에 Set Method 혹은 builder로 매핑하는 코드가 길어집니다.

이제부터 더 간결한 코드를 고민하는 시간을 가지며 위 문제점들을 개선한 내용을 정리하고자 합니다.

너무 많고 많은 DTO(VO)들..

프로젝트 내 VO 혹은 DTO 패키지 안에 필요할 때마다 Class파일을 생성하면 위 사진과 같이 파일수가 매우매우 많아집니다.

여기서 파생되는 문제점들은..

  • 일단 보기에 안좋습니다..(흐그는드)
  • 더 이상 ClassName이 중복되지 않는 DTO를 만들기가 어려워집니다.
  • 필드들이 겹치는 DTO로 대충 Response를 내리다보니 Over-Fetching을 하게됩니다.

DTO를 Inner Class로

그렇다면 같은 기능을 수행하며 DTO 패키지 내 클래스 파일을 깔끔하게 관리할 수 있는 방법이 있을까요?

 

필자가 주로 사용하는 방법은 Inner Class(Nested Class)로 DTO를 관리하는 것입니다.

간단한 예시로 User정보를 저장하는 api와 조회하는 api를 만드는 상황을 가정해봅시다!
떠오르는 DTO를 나열하자면

  1. POST Api에서 Request Payload를 매핑할 DTO
  2. GET Api에서 Return해줄 Response DTO
  3. 레이어를 옮겨다니거나 결과를 Return하기 위해 실제 User정보를 담은 DTO

홀리몰리.. 우리는 벌써 2~3개의 DTO을 생성하여야합니다..

하지만 User라는 도메인에 관련된 DTO들을 Class 하나에 묶어준다는 생각으로 User Class를 만든 후 Inner Class로 DTO들을 구현한다면..?\

 

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

public class User {

    @Getter
    @AllArgsConstructor
    @Builder
    public static class Info {
        private int id;
        private String name;
        private int age;
    }

    @Getter
    @Setter
    public static class Request {
        private String name;
        private int age;
    }

    @Getter
    @AllArgsConstructor
    public static class Response {
        private Info info;
        private int returnCode;
        private String returnMessage;
    }
}

 

import com.parksh.demo.dto.DefaultResponse;
import com.parksh.demo.dto.user.User;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(“user”)
public class UserController {

    @GetMapping(“/{user_id}”)
    public User.Response getUser(@PathVariable(“user_id”) String userId) {

        return new User.Response(new User.Info(), 200, “success”);
    }

    @PostMapping
    public DefaultResponse addUser(@RequestBody User.Info info) {

        return new DefaultResponse();
    }
}

(Controller 구현 부분)

이 방법을 채택하여 DTO를 관리한다면 조금 더 깔끔한 패키지를 만들 수 있고, DTO ClassName을 정하는게 수월해질 것입니다.
(귀찮아서 Over-Fetching을 하지 맙시다!)

 

Reference : velog.io/@ausg/Spring-Boot%EC%97%90%EC%84%9C-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-DTO-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0