Spring MVC
MVC 패턴이란?
MVC 패턴은 Model-View-Controller의 약자로, 소프트웨어 개발에서 흔히 사용되는 디자인 패턴입니다. 복잡한 애플리케이션을 세 가지 주요 구성 요소로 나누어 관리함으로써 코드의 유지보수성과 확장성을 높이는 데 효과적입니다.
- Model: 데이터를 표현하고 비즈니스 로직을 담당하는 부분입니다. 데이터베이스와의 상호 작용, 데이터 검증 등의 작업을 수행합니다.
- View: 사용자 인터페이스를 담당하는 부분입니다. 사용자에게 보여지는 화면을 구성하고, 사용자의 입력을 받습니다.
- Controller: 사용자의 요청을 받아 모델과 뷰를 연결하는 역할을 합니다. 사용자의 요청을 분석하고, 모델을 업데이트하며, 적절한 뷰를 선택하여 응답합니다.
서블릿/JSP와 MVC 패턴
서블릿과 JSP는 자바 웹 개발에서 MVC 패턴을 구현하는 데 널리 사용되는 기술입니다.
- 서블릿 (Servlet): 주로 Controller 역할을 수행합니다. 사용자의 요청을 받아 처리하고, 모델을 업데이트하며, 적절한 뷰(JSP)를 선택하여 응답합니다.
- JSP (JavaServer Pages): 주로 View 역할을 수행합니다. 동적인 HTML 페이지를 생성하며, 모델에서 제공하는 데이터를 화면에 출력합니다.
서블릿/JSP를 이용한 MVC 패턴 구현 예시
- 사용자가 웹 브라우저를 통해 요청을 보냅니다. (예: 회원 가입 페이지 요청)
- 웹 서버는 요청을 받아 해당 서블릿을 호출합니다.
- 서블릿은 요청을 분석하고, 필요한 모델 객체를 생성하여 데이터베이스에 접근하거나 비즈니스 로직을 수행합니다.
- 서블릿은 처리 결과를 모델 객체에 저장하고, 적절한 JSP 파일을 선택합니다.
- JSP 파일은 모델 객체에서 데이터를 가져와 동적인 HTML 페이지를 생성하고, 브라우저로 전송합니다.
- 브라우저는 받은 HTML 페이지를 해석하여 사용자에게 보여줍니다.
MVC 패턴의 장점
- 역할 분리: 각 구성 요소의 역할이 명확하게 분리되어 있어 코드의 가독성이 높아지고 유지보수가 용이합니다.
- 재사용성: 모델과 뷰를 분리하여 개발하기 때문에 각각의 구성 요소를 다른 애플리케이션에서 재사용할 수 있습니다.
- 테스트 용이성: 각 구성 요소를 독립적으로 테스트할 수 있어 개발 과정에서 발생할 수 있는 오류를 빠르게 찾아낼 수 있습니다.
- 확장성: 새로운 기능을 추가하거나 시스템을 변경할 때 각 구성 요소에 대한 영향을 최소화할 수 있습니다.
결론
MVC 패턴은 서블릿/JSP를 이용한 웹 애플리케이션 개발에서 필수적인 디자인 패턴입니다. MVC 패턴을 적용하면 코드의 품질을 향상시키고 개발 생산성을 높일 수 있습니다.
Spring Framework의 MVC 패턴 (이거 하나만 이해해도 된다.)
동작 순서
- Client로부터 요청이 들어오면 DispatcherServlet이 호출됩니다.
- DispatcherServlet은 받은 요청을 HandlerMapping에게 던져 주고, 요청 받은 URL을 분석하여 HandlerMapping의 적합한 Controller를 선택하여 반환합니다.
- DispatcherServlet는 다음으로 HandlerAdapter를 호출하고 HandlerApdater는 해당하는 Controller 중 요청한 URL에 맞는 적합한 Method를 찾습니다.
- Controller는 Business Logic을 처리하고, 해당하는 결과를 View에 전달할 객체를 Model에 저장합니다.
- Controller는 View name을 DispatcherServlet에게 리턴합니다.
- DispatcherServlet은 ViewResolver를 호출하여 Controller가 리턴한 View name을 기반으로 적합한 View를 찾습니다.
- DispatcherServlet은 View 객체에 처리 결과를 넘겨 최종 결과를 보여주도록 요청합니다.
- View 객체는 해당하는 View를 호출하며, View는 Model 객체에서 화면 표시에 필요한 객체를 가져와 화면 표시를 처리하고 Client에게 넘겨줍니다.
Spring MVC가 클라이언트의 웹 요청을 효율적으로 처리하고 응답을 생성하는 과정
a. Request (요청):
Request는 클라이언트(웹 브라우저 등)가 서버에 보내는 요청입니다. 웹 페이지를 요청하거나, 데이터를 전송하거나, 특정 작업을 수행하도록 서버에 지시하는 행위를 포함합니다. Spring MVC에서 Request는 HttpServletRequest 객체로 표현됩니다.
Request는 다음과 같은 정보를 포함합니다.
- URL (Uniform Resource Locator): 요청된 리소스의 주소입니다. (예: http://localhost:8080/welcome)
- HTTP Method: 요청의 종류를 나타냅니다. (예: GET, POST, PUT, DELETE)
- Headers: 요청에 대한 추가 정보를 담고 있는 헤더입니다. (예: Content-Type, User-Agent)
- Parameters: 요청과 함께 전달되는 데이터입니다. URL 쿼리 파라미터 또는 폼 데이터 형태로 전달될 수 있습니다.
- Body: 요청과 함께 전송되는 데이터 본문입니다. 주로 POST 요청에서 사용되며, JSON, XML 등의 형태로 데이터를 전송할 수 있습니다.
b. Response (응답):
Response는 서버가 클라이언트의 Request에 대한 처리 결과를 담아 보내는 응답입니다. Spring MVC에서 Response는 HttpServletResponse 객체로 표현됩니다.
Response는 다음과 같은 정보를 포함합니다.
- Status Code: 요청 처리 결과를 나타내는 상태 코드입니다. (예: 200 OK, 404 Not Found, 500 Internal Server Error)
- Headers: 응답에 대한 추가 정보를 담고 있는 헤더입니다. (예: Content-Type, Content-Length)
- Body: 클라이언트에 전송되는 데이터 본문입니다. HTML, JSON, XML 등의 형태로 데이터를 전송할 수 있습니다.
c. DispatcherServlet (디스패처 서블릿):
DispatcherServlet은 Spring MVC의 핵심 구성 요소입니다. 모든 웹 요청을 받아 적절한 핸들러(Controller)에 전달하는 역할을 합니다. 마치 "중앙 관제탑"과 같은 역할을 한다고 생각하면 이해하기 쉽습니다.
DispatcherServlet의 동작 과정은 다음과 같습니다.
- 클라이언트의 요청이 웹 서버에 도착합니다.
- 웹 서버는 요청을 DispatcherServlet에 전달합니다.
- DispatcherServlet은 Handler Mapping을 통해 요청을 처리할 적절한 핸들러(Controller)를 찾습니다.
- DispatcherServlet은 Handler Adapter를 사용하여 찾은 핸들러를 실행합니다.
- 핸들러는 요청을 처리하고 결과를 반환합니다.
- DispatcherServlet은 View Resolver를 사용하여 결과를 렌더링할 View를 찾습니다.
- DispatcherServlet은 View를 사용하여 응답을 생성하고 클라이언트에 반환합니다.
d. Handler Mapping (핸들러 매핑):
Handler Mapping은 DispatcherServlet이 요청을 처리할 적절한 핸들러(Controller)를 찾기 위해 사용하는 컴포넌트입니다. URL과 핸들러 간의 매핑 정보를 가지고 있으며, 요청 URL에 따라 어떤 핸들러를 실행해야 하는지 결정합니다.
Spring MVC는 다양한 Handler Mapping 구현체를 제공합니다. 주요한 몇 가지는 다음과 같습니다.
- RequestMappingHandlerMapping: @RequestMapping 어노테이션을 사용하여 매핑 정보를 설정하는 방식입니다. 가장 많이 사용되는 방식입니다.
- SimpleUrlHandlerMapping: URL 패턴과 핸들러 빈 이름을 직접 매핑하는 방식입니다.
e. Handler Adapter (핸들러 어댑터):
DispatcherServlet은 다양한 형태의 핸들러(Controller)를 처리할 수 있어야 합니다. 예를 들어, 어노테이션 기반 컨트롤러(@Controller) 외에도 이전 버전의 Spring에서 사용하던 Controller 인터페이스를 구현한 핸들러 등 다양한 방식이 존재합니다. Handler Adapter는 이러한 다양한 형태의 핸들러를 실행할 수 있도록 중간에서 어댑터 역할을 합니다. 즉, DispatcherServlet은 Handler Adapter를 통해 어떤 형태의 핸들러든 일관된 방식으로 실행할 수 있습니다.
주요 Handler Adapter는 다음과 같습니다.
- RequestMappingHandlerAdapter: @RequestMapping 어노테이션 기반 컨트롤러를 처리합니다. (가장 많이 사용)
- HttpRequestHandlerAdapter: HttpRequestHandler 인터페이스를 구현한 핸들러를 처리합니다.
- SimpleControllerHandlerAdapter: Controller 인터페이스를 구현한 핸들러를 처리합니다.
f. Controller (컨트롤러):
Controller는 클라이언트의 요청을 처리하는 핵심적인 역할을 합니다. 사용자의 요청을 분석하고, 필요한 비즈니스 로직을 수행하며, 그 결과를 Model에 담아 View에 전달합니다. Spring MVC에서는 @Controller 어노테이션을 사용하여 컨트롤러를 정의합니다.
예시:
@Controller
public class MyController {
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("message", "안녕하세요!"); // Model에 데이터 추가
return "hello"; // View 이름 반환
}
}
g. Model (모델):
Model은 Controller가 View에 전달할 데이터를 담는 그릇입니다. Key-Value 형태로 데이터를 저장하며, View는 Model에 담긴 데이터를 사용하여 화면을 구성합니다. Spring MVC에서는 Model 인터페이스를 사용하여 Model 객체를 생성합니다.
위의 예시에서 model.addAttribute("message", "안녕하세요!");는 "message"라는 키에 "안녕하세요!"라는 값을 Model에 저장하는 코드입니다.
h. View Resolver (뷰 리졸버):
View Resolver는 Controller가 반환한 View 이름을 기반으로 실제 View 객체를 찾아주는 역할을 합니다. 예를 들어, Controller가 "hello"라는 View 이름을 반환하면, View Resolver는 "hello"에 해당하는 View를 찾아 DispatcherServlet에 반환합니다.
주요 View Resolver는 다음과 같습니다.
- InternalResourceViewResolver: JSP를 사용하는 경우 사용됩니다.
- ThymeleafViewResolver: Thymeleaf를 사용하는 경우 사용됩니다. (현재 상황에 해당)
i. View (뷰):
View는 Model에 담긴 데이터를 사용하여 클라이언트에게 보여줄 화면을 생성하는 역할을 합니다. HTML, JSP, Thymeleaf 템플릿 등이 View의 역할을 할 수 있습니다.
Thymeleaf와 View의 관계:
Thymeleaf는 템플릿 엔진으로서 View의 역할을 합니다. Controller가 Model에 데이터를 담아 View에 전달하면, Thymeleaf는 템플릿 파일을 해석하고 Model의 데이터를 동적으로 삽입하여 최종 HTML을 생성합니다.
예시 (hello.html - Thymeleaf 템플릿):
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello</title>
</head>
<body>
<h1 th:text="${message}"></h1>
</body>
</html>
th:text="${message}" 는 Model에 "message"라는 키로 저장된 값을 HTML에 출력하는 Thymeleaf 표현식입니다.
※ 전체 흐름 (Thymeleaf 포함):
- hello 메서드는 Model에 "message"를 추가하고 "hello"라는 View 이름을 반환합니다.
- View Resolver(ThymeleafViewResolver)가 "hello"에 해당하는 View (hello.html)를 찾습니다.
- 생성된 HTML이 클라이언트에게 응답으로 전송됩니다.
요청 처리 흐름 정리:
클라이언트의 요청이 Spring MVC 애플리케이션에 들어왔을 때, 다음과 같은 흐름으로 처리됩니다.
- Request 발생: 클라이언트가 웹 브라우저를 통해 특정 URL을 요청합니다. (예: 클라이언트가 /hello를 요청)
- DispatcherServlet 수신: 웹 서버는 요청을 DispatcherServlet에 전달합니다.
- Handler Mapping: DispatcherServlet은 Handler Mapping을 통해 요청 URL, HTTP 메서드 등을 분석하여 해당 요청을 처리할 핸들러(Controller)의 메서드를 찾습니다.
- Handler Adapter 실행: DispatcherServlet은 Handler Adapter를 사용하여 찾은 핸들러의 메서드를 실행합니다. Handler Adapter는 다양한 형태의 핸들러를 실행할 수 있도록 중간 역할을 합니다.
- Controller 처리: 핸들러(Controller)는 요청을 처리하고 Model에 데이터를 담거나 View 이름을 반환합니다.
- View Resolver: DispatcherServlet은 ViewResolver를 사용하여 View 이름을 기반으로 View 객체를 찾습니다. (예: ThymeleafView 객체)
- View 렌더링: View 객체는 Model에 담긴 데이터를 사용하여 응답을 생성합니다. (예: Thymeleaf가 hello.html 템플릿을 해석하고 Model의 "message" 값을 삽입하여 HTML을 생성)
- Response 전송: 생성된 응답이 클라이언트에게 전송됩니다.
수업에선 다음과 같이 프로젝트를 생성해주었다.