[스프링부트]Model → DTO, 공통 응답 DTOModel → DTO, 공통 응답 DTO

송송승현's avatar
Nov 25, 2024
[스프링부트]Model → DTO, 공통 응답 DTOModel → DTO, 공통 응답 DTO

Model

💡
데이터 베이스와 직접적으로 매핑되는 객체로 , 주로 비즈니스 로직과 데이터베이스 상호작용을 관리

DTO

💡
네트워크를 통해 데이터를 전송하거나 계층 간에 데이터를 전달하기 위해 사용되는 객체
비즈니스 로직을 포함하지 않으며, 단순히 데이터 전송만을 목적

Model → DTO에 대한 상관관계

데이터 캡슐화 및 추상화

  • Model과 DTO를 분리함으로써 데이터 캡슐화가 이루어지며, 유지보수성과 확장성 상승

계층간 결합도 감소

  • Model과 DTO를 분리함으로써 데이터 계층과 비즈니스 로직 계층 간의 결합도 줄임. 이를 통해 각 계층이 독립적으로 변화될 수 있으며, 다른 계층에 영향X

보안 및 데이터 무결성

  • 민감한 데이터의 유출을 방지할 수 있으며, 데이터 전송 시 데이터 무결성을 유지

예제

@Data @AllArgsConstructor public class Product { private int id; private String name; // 바지 } @Data @AllArgsConstructor public class ProductOption { private int id; private String name; private int price; private int qty; private Product product; @Data @AllArgsConstructor public class Order { private int id; } @Data @AllArgsConstructor public class OrderOption { private int id; private Product product; private String optionName; // 하얀티 private int qty; // 5개 private int totalPrice; // 10000원 private Order order; } @Data public class OrderDetailDTO { private int orderId; private List<OrderProductDTO> products = new ArrayList<>(); private int sumPrice; public OrderDetailDTO(List<OrderOption> options) { // 1. orderId this.orderId = options.get(0).getOrder().getId(); // 2. sumPrice for (OrderOption option : options) { this.sumPrice += option.getTotalPrice(); } // 3. products // 3.1 주문옵션들 productId [1,1,2] -> [1,2] 돈봉투 2개 만들기 Set<Integer> ids = new HashSet<>(); // [1,2] for (OrderOption option : options) { ids.add(option.getProduct().getId()); } // 3.2 중복된 상품의 크기만큼 반복하면서 주문 옵션 추가하기 for (Integer id : ids) { List<OrderOption> temp = new ArrayList<>(); for (OrderOption option : options) { if(id == option.getProduct().getId()) temp.add(option); } OrderProductDTO product = new OrderProductDTO(temp); products.add(product); } } @Data class OrderProductDTO { // 돈봉투 private int productId; private List<OrderOptionDTO> options = new ArrayList<>(); public OrderProductDTO(List<OrderOption> options) { this.productId = options.get(0).getProduct().getId(); for (OrderOption option : options) { this.options.add(new OrderOptionDTO(option)); } } @Data class OrderOptionDTO{ private int id; private String optionName; private int qty; private int totalPrice; public OrderOptionDTO(OrderOption option) { this.id = option.getId(); this.optionName = option.getOptionName(); this.qty = option.getQty(); this.totalPrice = option.getTotalPrice(); } } } } public class App1 { public static void main(String[] args) { Product p1 = new Product(1, "바지"); Product p2 = new Product(2, "티"); // 2. 옵션 4개 생성 (2-1, 2-2) ProductOption op1 = new ProductOption(1,"파란바지", 1000, 10, p1); ProductOption op2 = new ProductOption(2, "빨간바지", 2000, 10, p1); ProductOption op3 = new ProductOption(3, "노랑티", 1000, 10, p2); ProductOption op4 = new ProductOption(4, "하얀티", 2000, 10, p2); // 3. 구매 Order or1 = new Order(1); OrderOption orOption1 = new OrderOption(1,p1, "파란바지", 2, 2000, or1); OrderOption orOption2 = new OrderOption(2,p1, "빨간바지", 2, 4000, or1); OrderOption orOption3 = new OrderOption(3,p2, "하얀티", 5, 10000, or1); op1.setQty(op1.getQty() - 2); op2.setQty(op2.getQty() - 2); op4.setQty(op4.getQty() - 5); Order or2 = new Order(2); OrderOption orOption4 = new OrderOption(4,p2, "노랑티", 7, 7000, or2); List<OrderOption> or2Options = Arrays.asList(orOption4); op3.setQty(op3.getQty() - 7); Gson gson = new Gson(); List<OrderOption> or1Options = Arrays.asList(orOption1, orOption2, orOption3); OrderDetailDTO orderDetailDTO = new OrderDetailDTO(or1Options); String r3 = gson.toJson(orderDetailDTO); System.out.println(r3); } }

공통 응답 DTO

💡
여러 API 엔드포인트에서 공통으로 사용할 수 있는 포맷을 정의한 객체
API응답의 일관성을 유지 할 수 있고, 코드의 재사용성 상승

필요성

  • 일관성 유지 : 모든 API 엔드 포인트에서 동일한 응답 형식을 사용함으로써 클라이언트는 응답구조를 예측
  • 에러처리 : 일관된 형식을 통해 에러 응답을 표준화

구조

  • state : 요청의 성공 or 실패 상태
  • message : 요청에 대한 설명 메세지
  • data : 요청에 대한 데이터

예제

import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class Resp<T> { // state : 요청의 성공, 실패를 boolean값으로 private boolean success; // message : 요청에 대한 메세지 private String msg; // data : 요청에 대한 제네릭 타입의 데이터 private T body; // 성공 응답을 생성하는 메서드 public static <T> Resp<T> ok(T body) { return new Resp<>(true, "성공", body); } // 실패 응답을 생성하는 메서드 // 예외 발생시 이 코드 응답 public static <T> Resp<T> fail(String msg) { return new Resp<>(false, msg, null); } }
 
Share article

송승현의 블로그