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