DTO

 

DTO에 대해 설명하기 전에 MVC패턴을 이해할 필요가 있다.

MVC 패턴은 애플리케이션을 Model, Controller, View 세 가지로 구분하는 디자인 패턴이다.

 

  • Model : DB와 관련된 일을 한다.
  • View : 데이터를 받아서 표현하거나 사용자 요청을 받는다.
  • Contoller : Model에서 데이터를 받아 View로 전달해주거나 View에서 들어온 요청을 해석해 Model을 변경한다.
    비즈니스 처리로직(Model)과 UI(View)의 중간에서 Controller가 이들을 연결해주는 역할을 한다.

서로 분리함으로써 각자 역할에만 집중하게 하는 것이다.

이런 경우 유지보수, 확장, 유연성, 중복해결 등 다양한 측면에서 유리해진다.

 

DTO(Data Transfer Object) 란 이러한 계층간 데이터 교환을 위해 Controller 가 사용하는 객체이다.

 

"엥 그냥 주고받으면 되지 않나요?"

라고 생각할 수 있는데, 만약에 Model을 직접 넘겨주게 된다면 다음과 같은 문제점들이 발생한다.

  1. Model 의 모든 속성이 외부에 노출된다.
    UI 에서 필요로 하지 않는 데이터까지 보내주는 것에 더해  민감한 정보까지 외부에 노출될 수 있다.
    UI 계층에서 Model을 건드릴 수 있게 된다. 즉, 보안문제와 직결된다.

  2. Model 과 View 가 강하게 결합되어 의존성이 커진다.

DTO 를 사용하면 위의 문제들을 해결할 수 있다.

사실 저번에 배운 CRUD를 실행할 때도 소규모 프로젝트였기에 필요성을 못 느꼈을 뿐이지, Car 클래스를 막 사용하는건 바람직하지 않은 방법이었다.

 

고로 이번에는 완충재 역할을 할 DTO를 만들어보고자 한다.

 

models 패키지에 DTO파일을 만든다.

CarRequestDto.java

더보기
package com.eunki96.test02.models;

import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Getter
public class CarRequestDto {
    private String model;
    private String brand;

    public CarRequestDto(String model, String brand){
        this.model = model;
        this.brand = brand;
    }
}

 

이제 DTO를 통해 데이터를 주고받으려 한다.

이에 맞춰 나머지 파일들을 수정해준다.

직접 Car 클래스 객체들을 넘겨주던 부분을 DTO 로 대체하면 된다.

 

CarService.java

더보기
package com.eunki96.test02.service;

import com.eunki96.test02.domain.Car;
import com.eunki96.test02.domain.CarRepository;
import com.eunki96.test02.models.CarRequestDto;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@Service
public class CarService {

    private final CarRepository carRepository;
    
    public CarService(CarRepository carRepository){
    
        this.carRepository = carRepository;
        
    }
    
    @Transactional
    public void update(Long id, CarRequestDto carRequestDto){ 
    
    	//ID 와 Car 클래스를 사용했지만, 이제는 DTO를 사용한다.

        Car car1 = carRepository.findById(id).orElseThrow(
                () -> new IllegalArgumentException("해당 아이디가 존재하지 않음.")
        );

        car1.update(carRequestDto);
    }
}

 

 

Car.java

더보기
package com.eunki96.test02.domain;

import com.eunki96.test02.models.CarRequestDto;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@NoArgsConstructor
@Entity
@Getter
public class Car extends Timestamped{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false)
    private String model;

    @Column(nullable = false)
    private String brand;

    public Car (String model, String brand){
        this.model = model;
        this.brand = brand;
    }

	//Car 클래스를 사용했지만, 이제는 DTO를 사용한다.
    public void update(CarRequestDto carRequestDto){
        this.model = carRequestDto.getModel();
        this.brand = carRequestDto.getBrand();
    }

}

 

Test02Application.java

더보기
package com.eunki96.test02;

import com.eunki96.test02.domain.Car;
import com.eunki96.test02.domain.CarRepository;
import com.eunki96.test02.models.CarRequestDto;
import com.eunki96.test02.service.CarService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import java.util.List;

@EnableJpaAuditing
@SpringBootApplication
public class Test02Application {

    public static void main(String[] args) {
        SpringApplication.run(Test02Application.class, args);
    }

    @Bean
    public CommandLineRunner demo(CarRepository carRepository, CarService carService) {
        return (args) -> {
            carRepository.save(new Car("718 Boxster GTS", "Porsche"));
            carRepository.save(new Car("Escalade", "Cadillac"));
            carRepository.save(new Car("S Class", "Mercedes benz"));
            carRepository.save(new Car("MC20", "Maserati"));
            carRepository.save(new Car("Wraith", "Rolls-Royce"));

		//Car 클래스를 사용했지만, 이제는 DTO를 사용한다.
            CarRequestDto carRequestDto = new CarRequestDto("Maybach", "Mercedes benz");
            carService.update(3L, carRequestDto);

            carRepository.deleteById(4L);
        };
    }

}

 

DTO를 사용하여 저번과 같은 결과를 만들었다.

다음으로는 API 와 REST 를 더 자세히 알아보려고 한다.