API를 만들기 위해선 총 3개의 클래스가 필요하다.
- Request 데이터를 받을 Dto
- Api 요청을 받을 Controller
- 트랜잭션, 도메인 기능 간의 순서를 보장하는 Service
우리가 흔히 하는 오해가 있다. 비즈니스 로직은 Service에서 처리하는 것이 아니다. 도메인에서 처리해야한다.
이를 위한 예시를 살펴보자
주문을 취소하는 비즈니스 로직을 개발해보자. 슈도코드로 로직을 구현하면 아래와 같다.
@Transactional
public Order cancelOrder(int orderId){
1) 데이터베이스로부터 주문정보(Orders), 결제정보(Billing), 배송정보(Delivery)조회
2) 배송 취소를 해야하는지 확인
3) if(배송 중이라면){
배송 취소로 변경
}
4) 각 테이블에 취소 상태 update
}
서비스에서 비즈니스를 처리하는 로직
- 모든 로직이 서비스 클래스 내부에서 처리된다. 이렇게 되면 서비스 계층이 무의미하며, 객체는 단순히 데이터 덩어리 역할만 하게 된다.
@Transactional
public Order cancelOrder(int orderId){
//1)DB로부터 주문정보, 결제정보, 배송정보 조회
OrderDto order = orderDao.selectOrders(orderId)
Billing billing = bilingDao.selectBilling(orderId);
Delivery delivery = deliveryDao.selectDelivery(orderId);
//2)배송취소 확인
String deliveryStatus = delivery.getStatus();
//3)배송중이라면 배송 취소로 변경
if("IN_PREGRESS".equals(deliveryStatus)){
delivery.setStatus("CANCEL");
deliveryDao.update(delivery);
}
//4)각 테이블에 취소 상태 update
order.setStatus("CANCEL");
orderDao.update(order);
billing.setStatus("CANCEL");
billingDao.update(billing);
return order;
}
도메인에서 비즈니스를 처리하는 로직
- order, billing, delivery가 각자 본인의 취소 이벤트 처리를 하며, 서비스 메소드는 트랜잭션과 도메인 순서만 보장을 해준다.
@Transactional
public Order cancelOrder(int orderId){
//1)DB로부터 주문정보, 결제정보, 배송정보 조회
OrderDto order = orderRepository.findById(orderId);
Billing billing = billingRepository.findByOrderId(orderId);
Delivery delivery = deliveryRepository.findByOrderId(orderId);
//2,3)배송취소 확인 후 배송중이라면 배송 취소로 변경
delivery.cancle();
//4)각 테이블에 취소 상태 update
order.cancle();
billing.cancle();
return order;
}
Spring 웹 계층에 대해 알아보자
1. Web Layer
- 웹 어플리케이션의 최상위에 존재한다. 외부 요청과 응답에 대한 전반적인 영역이며 어플리케이션의 진입점이기 때문에 다른 레이어에서 발생한 예외도 처리한다. 인증을 관리하고 권한없는 사용자의 인가를 거부하는 역할도 한다.
- controllers, exception handlers, filters, view templates, etc
- 컨트롤러(@Controller)와 JSP/Freemarker등의 뷰 템플릿 영역이다.
- 필터(@Filter), 인터셋터, 컨트롤러 어드바이스(@ControllerAdvice)등 외부 요청과 응답에 대한 전반적인 영역이다.
- 데이터 전송 객체만 처리해야 한다.
2. Service Layer
- Web Layer 바로 아래 존재하는 객체이다. 트랜잭션에 대한 경계 역할, 어플리케이션과 인프라 서비스 모두 포함하고 있다.
- application service and infrastructure service
- @Service에 사용되는 서비스 영역이다. 일반적으로 Controller와 Dao 중간 영역에서 사용된다.
- @Transaction이 사용되어야 하는 영역이기도 하다.
- 데이터 전송 객체를 메소드의 매개변수로 사용한다. 도메인 모델 객체를 처리한다.
3. Repository Layer
- 가장 낮은 계층으로 사용되는 데이터 스토리지 계층과 통신하는 역할이다. Database와 같이 데이터 저장소에 접근하는 영역이다.
- Dao(Data Access Object)영역이라고 생각하면 된다.
- 엔티티를 메소드 매개변수로 가져올 수 있고 엔티티를 리턴한다.
4. Dtos
- Data Tansfer Object의 약자로, 계층 간에 데이터 교환을 위한 객체이다.
- 예를 들어 뷰 템플릿 엔진에서 사용될 객체나 Repository Layer에서 결과로 넘겨준 객체 들을 의미한다.
5. Domain Model
- Domain services, entities, VO(DTO와 동일한 개념이나 read only 속성을 가진다.)
- 도메인이라 불리는 개발 대상을 모든 사람이 동일한 관점에서 이해할 수 있고 공유할 수 있도록 단순화시킨 것을 도메인 모델이라 한다.
- 예를들어 택시 앱이라고 하면, 배차, 탑승, 요금 등이 모두 도메인이 된다.
- @Entity가 사용된 영역을 도메인 모델이라고 한다.
- 다만, 무조건 데이터베이스 테이블과 관계가 있는건 아니다. VO처럼 값 개체들도 이 영역에 해당한다.
참고
스프링 부트와 AWS로 혼자 구현하는 웹서비스
'Project > SpringBoot를 사용해서 웹 서비스를 만들어보자' 카테고리의 다른 글
[코드 분석]Stream, map, collect (0) | 2023.08.22 |
---|---|
템플릿 엔진이란 (0) | 2023.08.22 |
자주 사용하는 Lombok 어노테이션 정리 (0) | 2023.08.17 |
JPA Auditing (0) | 2023.08.17 |
springboot lombok symbol method builder() 에러 해결 (0) | 2023.08.14 |