DTO란?

·2023년 7월 10일
1

프로젝트 공부

목록 보기
8/33

DTO

DTO는 로직을 갖고 있지 않는 순수한 데이터이며, Getter/Setter만을 갖는다.

DTO = Data Transfer Object
계층 간 데이터 교환을 위한 객체(Java Beans)다.

  • DB에서 데이터를 얻어 Service나 Controller 등으로 보낼 때 사용하는 객체를 말한다.
  • 즉, DB의 데이터가 Presentation Logic Tier로 넘어오게 될 때는 DTO의 모습으로 바껴서 오고가는 것이다.
  • 로직을 갖고 있지 않는 순수한 데이터 객체이며, getter/setter 메서드만을 갖는다.
  • 하지만 DB에서 꺼낸 값을 임의로 변경할 필요가 없기 때문에 DTO클래스에는 setter가 없다. (대신 생성자에서 값을 할당한다.)

예시

@Controller
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;

    @GetMapping("/members/new") //회원 가입
    public String createForm(Model model) {
        model.addAttribute("memberForm", new MemberForm());
        return "members/createMemberForm";
    }
}
    
@Getter @Setter
public class MemberForm {

    @NotEmpty(message = "회원 이름은 필수입니다")
    private  String name;

    private  String city;
    private  String street;
    private  String zipcode;
}

위 코드의 memberForm과 같이 실제 엔티티가 아닌 오로지 전달을 목적으로 하는 객체를 말하며 DTO를 통해 구현한다.

❗참고: 폼 객체 vs 엔티티 직접 사용

참고: 요구사항이 정말 단순할 때는 폼 객체( MemberForm ) 없이 엔티티( Member )를 직접 등록과 수정 화면에서 사용해도 된다. 하지만 화면 요구사항이 복잡해지기 시작하면, 엔티티에 화면을 처리하기 위한 기능이 점점 증가한다. 결과적으로 엔티티는 점점 화면에 종속적으로 변하고, 이렇게 화면 기능 때문에 지저분해진 엔티티는 결국 유지보수하기 어려워진다.

실무에서 엔티티는 핵심 비즈니스 로직만 가지고 있고, 화면을 위한 로직은 없어야 한다. 화면이나 API에 맞는 폼 객체나 DTO를 사용하자.
그래서 화면이나 API 요구사항을 이것들로 처리하고, 엔티티는 최대한 순수하게 유지하자.

DTO를 Inner Class로 -> 깔끔하게 관리

API별로 화면에 return하는 데이터가 달라 많은 DTO 파일을 생성할 수 있다.

  • 너무 많은 DTO는 가독성에서 좋지 않고
  • ClassName이 중복되지 않는 DTO를 만들기 어려워지며
  • 필드들이 겹치는 DTO로 대충 Response를 내리게 되면 Over-Fetchcing이 될 수 있다
    => 같은 기능을 수행하는 DTO들을 Inner class로 묶어 관리하자

예시

만약 User 정보를 저장하는 api, 조회하는 api를 만드는 상황에서 필요한 DTO는

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

가 될 것이다. 이 세 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;
    }
}

이와 같이 1개의 Class 파일로 깔끔하게 관리할 수 있게 된다.

Inner Class를 사용한 Controller 구현 예시

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();
    }
}

참고
[DAO] DAO, DTO, Entity Class의 차이
DTO
Spring Boot에서 깔끔하게 DTO 관리하기

profile
개발자가 되고싶은 낭랑 24세

0개의 댓글

관련 채용 정보