[Spring] Spring MVC 에서 클라이언트와 서버 간 데이터를 어떻게 주고 받을까?

Spring MVC에서 클라이언트와 서버 간 데이터를 어떻게 주고받는 지 예시를 통해 알아보자. 추가적으로, 왜 DTO를 통해 데이터를 주고받아야 하는지 살펴보자.
Hi's avatar
Apr 23, 2024
[Spring] Spring MVC 에서 클라이언트와 서버 간 데이터를 어떻게 주고 받을까?
 

✅ Spring MVC

📋
Spring MVC, 많은 다른 웹 프레임워크와 마찬가지로 중앙 컨트롤러 패턴을 기반으로 설계되었다. 여기서 중앙 Servlet 인 DispatcherServlet은 요청 처리를 위한 공유 알고리즘을 제공하며 실제 작업은 구성 가능한 대리 구성 요소에 의해 수행된다.
 

✅ 클라이언트가 요청을 보내면?

notion image

프레젠테이션 계층

  • 브라우저상의 웹 클라이언트의 요청 및 응답을 처리
  • 서비스계층, 데이터 엑세스 계층에서 발생하는 Exception을 처리
  • @Controller 어노테이션을 사용하여 작성된 Controller 클래스가 이 계층에 속함

서비스 계층

  • 애플리케이션 비즈니스 로직 처리와 비즈니스와 관련된 도메인 모델의 적합성 검증
  • 트랜잭션 관리
  • 프레젠테이션 계층과 데이터 엑세스 계층 사이를 연결하는 역할로서 두 계층이 직접적으로 통신하지 않게 함
  • Service 인터페이스와 @Service 어노테이션을 사용하여 작성된 Service 구현 클래스가 이 계층에 속함

레포지토리 계층

  • ORM (Mybatis, Hibernate)를 주로 사용하는 계층
  • DAO 인터페이스와 @Repository 어노테이션을 사용하여 작성된 DAO 구현 클래스가 이 계층에 속함
  • Dabase에 data를 CRUD(Create, Read, Update, Drop)하는 계층
 
요청 처리를 위한 DispatcherServlet의 역할을 간단히 요약해보자면:
  1. 클라이언트가 요청을 보내면 해당 요청은 Servlet 컨테이너에 의해 DispatcherServlet으로 전달된다.
  1. DispatcherServlet은 요청 URL을 검사하고 요청을 처리하기 위해 적절한 핸들러를 결정한다.
  1. 적절한 핸들러를 찾으면 DispatcherServlet은 요청을 해당 컨트롤러 메서드로 전달한다.
  1. 컨트롤러는 비즈니스 로직을 실행하고 필요한 데이터를 준비한 후 적절한 뷰를 선택하여 응답을 렌더링한다.
  1. 렌더링된 뷰가 클라이언트에게 반환된다.
 

✅ DTO로 데이터를 주고 받는 이유

📋
일반적으로 클라이언트와 서버 간 데이터를 주고 받을 때 DTO 혹은 VO라는 별도의 객체를 통해 주고 받는다. 그 중에서도 Repository 계층과 DB가 주고받는 형식은 Domain(또는 Entity)라는 별도의 객체를 통해 주고 받는다.
 
notion image
Domain 클래스와 DTO 클래스를 분리하는 이유
  • 테이블과 매핑되는 Entity 클래스가 변경되면 여러 클래스에 영향을 끼치게 되지만 View와 통신하는 DTO 클래스는 자주 변경되므로 분리해야 한다.
  • 즉, DTO는 Domain Model을 복사한 형태로, 다양한 Presentation Logic을 추가한 정도로 사용하며 Domain Model 객체는 Persistent만을 위해서 사용한다.
 

✅ CRUD 예시

Product라는 데이터를 CRUD 할 수 있는 Spring MVC 기반 서버를 구축했다고 가정해보자. (필자는 실제로 구축하였다.)
 
사용자가 원하는 상품을 DB에 추가 등록하는 상황을 가정해보자.
 
  1. 상품 등록 버튼 클릭 (‘http://localhost:8080/mvc/product/create’로 POST Request 전송으로 대체)
  1. 등록을 원하는 상품의 상세 정보 입력(Front에서 ProductRequestMvc 형식의 Json으로 객체 매핑 후 서버로 전송)
  1. API Server의 Controller에서 해당 Request 수신 후 위url에 해당하는 메소드 ‘createProduct( )’ 호출
  1. Controller 계층에서 Service 계층의 ‘create( )’ 메소드 호출, 이때 인자로 ProductRequestMvc 객체의 속성을 넘겨줌.
  1. Service 계층에서 ProductEntityMvc 객체를 생성하여 Repository 계층의 ‘save( )’ 메소드 호출
  1. Repository 계층에서 상품 저장 후, ProductEntityMvc 객체 리턴
  1. Service 계층에서 Repository 계층에서 리턴한 객체를 다시 리턴
  1. Controller 계층에서 리턴받은 ProductEntityMvc 객체를 Converter를 통해 ProductResponseMvc 객체 형식으로 리턴
  1. Front에서 받은 정보를 화면에 출력
 

1. 상품 등록 버튼 클릭 (‘http://localhost:8080/mvc/product/create’로 POST Request 전송으로 대체)

2. 등록을 원하는 상품의 상세 정보 입력(Front에서 ProductRequestMvc 형식의 Json으로 객체 매핑 후 서버로 전송)

notion image
 

3. API Server의 Controller에서 해당 Request 수신 후 위url에 해당하는 메소드 ‘createProduct( )’ 호출

4. Controller 계층에서 Service 계층의 ‘create( )’ 메소드 호출, 이때 인자로 ProductRequestMvc 객체의 속성을 넘겨줌.

notion image
 
 

5. Service 계층에서 ProductEntityMvc 객체를 생성하여 Repository 계층의 ‘save( )’ 메소드 호출

notion image
 

6. Repository 계층에서 상품 저장 후, ProductEntityMvc 객체 리턴

notion image
 

7. Service 계층에서 Repository 계층에서 리턴한 객체를 다시 리턴

notion image
 

8. Controller 계층에서 리턴받은 ProductEntityMvc 객체를 Converter를 통해 ProductResponseMvc 객체 형식으로 리턴

notion image
 

9. Front에서 받은 정보를 화면에 출력

 
notion image
 
 
이러한 과정을 거쳐 클라이언트와 서버 간 API를 통해 데이터를 주고받을 수 있다.
Share article

soultree