Spring에서 지원하는 모든 기능들을 포함해서 Spring Framework라고 부름. Spring의 모듈 중에서 웹 계층을 담당하는 몇 가지 모듈이 있음. 특히 서블릿(Servlet) API를 기반으로 클라이언트의 요청을 처리하는 모듈이 있는데, 이 모듈의 이름은 spring-webmvc
임. 개발자들 사이에서는 Spring Web MBV를 줄여서 Srping MVC라고 부르고 있고, Spring MVC가 웹 프레임워크의 한 종류이기 때문에 Spring MVC 프엠워크라고도 부름.
서블릿(Servlet)이란?
서블릿은 클라이언트의 요청을 처리하도록 특정 규약에 맞추어서 Java 코드로 작성하는 클래스 파일임. 그리고 아파치 톰캣 (Apache Tomcat)은 이러한 서블릿들이 웹 애플리케이션으로 실행이 되도록 해주는 서블릿 컨테이너(Servlet Container) 중 하나임.
Model은 Spring MVC에서 M에 해당됨.Spring MVC 기반의 웹 애플리케이션이 클라이언트의 요청을 전달받으면 요청 사항을 처리하기 위한 작업을 함. 이렇게 처리한 작업의 결과 데이터를 클라이언트에게 응답으로 돌려줘야하는데, 이 때 클라이언트에게 응답으로 돌려주는 작업의 처리 결과 데이터를 Model이라고 함. 클라이언트의 요청 사항을 구체적으로 처리하는 영역을 서비스 계층 (Service Layer)이라고 하며, 실제로 요청 사항을 처리하기 위해 Java 코드로 구현한 것을 비즈니스 로직(Business Logic)이라고 함.
View는 Spring MVC에서 V에 해당함. View는 Model 데이터를 이용해서 웹브라우저같은 클라이언트 애플리케이션의 화면에 보여지는 리소스(resource)를 제공하는 역할을 함. Spring MVC에는 다양한 View 기술이 포함되어 있는데 View의 형태는 아래와 같이 나눌 수 있음.
Json(JavaSript Object Notation)이란?
Spring MVC에서 클라이언트 애플리케이션과 서버 애플리케이션이 주고 받는 데이터 형식. 과거에는 XML 형식의 데이터가 많이 사용되었으나 현재는 XML보다 상대적으로 가볍고, 복잡하지 않은 JSON 형식을 대부분 사용하고 있음.
기본 포맷: {"속성":"값"}
public class Coffee {
private String korName;
private String engName;
private int price;
public Coffee(String korName, String engName, int price) {
this.korName = korName;
this.engName = engNmame;
this.price = price;
}
}
위 코드는 Coffee를 클래스로 표현한 코드임. 고객이 아메리카노 한잔을 주문하기 위해서 아메리카노의 정보를 요청한다면 서버 애플리케이션 쪽에서 아메리카노 정보를 JSON 형식으로 변환해서 전송해주어야 함.
public class JsonExample {
public static void main(String[] args) {
Coffee coffee = new Coffee("아메리카노", "Americano", 300);
Gson gson = Gson();
String jsonString = gson.toJson(coffee);
System.out.println(jsonString);
}
}
위 코드는 Gson이라는 라이브러리를 사용해서 Coffee 클래스의 객체를 JSON 포맷 형태로 출력하는 예제임.
코드 실행 결과
=============================================================
{"korName":"아메리카노","engName":"Americano","price":3000}
Controller는 Spring MVC에서 C에 해당됨. Controller는 클라이언트 측의 요청을 직접적으로 전달받는 엔드포인트(Endpoint)로써 Model과 View의 중간에서 상호 작용을 해주는 역할을 함. 즉, 클라이언트 측의 요청을 전달받아서 비즈니스 로직을 거친 후에 Model 데이터가 만들어지면 이 Model 데이터를 View로 전달하는 역할을 함
@RestController
@RequestMapping(path = "/v1/coffee")
public class CoffeeController {
private final CoffeeService coffeeService;
CoffeeController(CoffeeService coffeeService) {
this.coffeeService = coffeeService;
}
@GetMapping("/{coffee-id}") // (1)
public Coffee getCoffee(@PathVariable("coffee-id") long coffeeId) {
return coffeeService.findCoffee(coffeeId); // (2)
}
}
위 코드는 Spring MVC에서 Controller에 해당되는 영역을 코드로 작성한 예임. (1)의 @GetMapping
애노테이편을 통해 클라이언트 측의 요청을 수신함. (2)에서 CoffeeService
클래스의 findCoffee()
메서드를 호출해 비즈니스 로직을 처리함. (2)에서 비즈니스 로직을 처리한 다음 리턴받는 Coffee가 여기서는 Model 데이터가 됨. 그리고 getCoffee()
에서 이 Model 데이터를 리턴하는데, 리턴되는 이 Model 데이터는 우리가 코드 상에서는 확인할 수 없지만 내부적으로 Spring의 View가 전달받아서 JSON 포맷으로 변경한 후에 클라이언트 측에 저달함.
Client가 요쳥 데이터 전송 -> Controller가 요청 데이터 수신 -> 비즈니스 로직 처리 -> Model 데이터 생성 -> Controller에게 Model 데이터 전달 -> Controller가 View에게 Model 데이터 전달 -> View가 응답 데이터 생성
(1) 먼저 클라이언트가 요청을 전송하면 DispatcherServlet
이라는 콜래스에 요청이 전달됨
(2) DispatcherServlet
은 클라이언트의 요청을 처리할 Controller에 대한 검색을 HandlerMapping 인터페이스에게 요청함
(3) HandlerMapping
은 클라이언트 요청과 매핑되는 핸들러 객체를 다시 DispatcherServlet에게 리턴해줌. 핸들러 객체는 해당 핸들러의 Handler 메서드 정보를 포함하고 있음. Handler 메서드는 Controller 클래스 안에 구현된 요청 처리 메서드를 의미함.
(4) 요청을 처리할 Controller 클래스를 찾았으니 이제는 실제로 클라이언트 요청을 처리할 Handler 메서드를 찾아서 호출해야 함. DispatcherServlet
은 Handler 메서드를 직접 호출하지 않고, HandlerAdapter
에게 Handler 메서드 호출을 위임함.
(5) HandlerAdapter
는 DispatcherServelet으로부터 전달받은 Controller 정보를 기반으로 해당 Controller의 Handler 메서드를 호출함.
(6) Controller
의 Handler 메서드는 비즈니스 로직 처리 후 리턴받은 Model 데이터를 HandlerAdapter에게 전달함
(7) HandlerAdapter는 전달받은 Model 데이터와 View 정보를 다시 DispatcherSservlet에게 전달함.
(8) DispatcherServlet
은 전달받은 View 정보를 다시 ViewResolver에게 전달해서 View 검색을 요청함
(9) ViewResolver
는 View 정보에 해당하는 View만 찾아서 View를 다시 리턴해줌
(10) DispatcherServlet
은 ViewResolver로부터 전달받은 View 객체를 통해 Model 데이터를 넘겨주면서 클라이언트에게 전달할 응답 데이터 생성을 요청함
(11) View
는 응답 데이터를 생성해서 다시 DispatcherServlet에게 전달함
(12) DispatcherServlet
은 View로부터 전달받은 응답 데이터를 최종적으로 클라이언트에게 전달함
클라이언트로부터 요청을 전달받으면 HandlerMapping, HandlerAdapter, ViewResolver, View 등 대부분의 Spring MVC 구성 요소들과 상호 작용을 하고 있음. 그런데 DispatcherServlet이 바빠보이지만 실제로 요청에 대한 처리는 다른 구성 요소들에게 위임(Delegate)하고 있음. 이처럼 DispatcherServlet이 애플리케이션의 가장 앞단에 배치되어 다른 구성요소들과 상호작용하면서 클라이언트의 요청을 처리하는 패턴을 Front Controller Pattern이라고 함.