MVC Pattern
- Model: Business logic 실행, 데이터 처리, 결과 데이터 생성
- View: User interface 생성(presentation logic 실행), 출력 화면 생성
- Controller: Request 처리, request/response 데이터 전달
Spring MVC 주요 구성요소
- DispatcherServlet: Client의 요청(request)을 받아 Contoller에게 전달. Controller의 처리 결과를 View에 전달하여 응답(response)을 생성하도록 함(front controller)
- HandlerMapping: Client의 요청 URL을 어떤 Controller가 처리할지를 결정
- HandlerAdapter: DispatcherServlet과 Controller사이에서 요청과 응답 결과를 적절한 형식으로 변환
- Controller: Client의 요청을 처리한 후 그 결과를 DispatcherServlet에게 전달
- ModelAndView: Controller가 처리한 결과 및 View 선택에 필요한 정보를 포함하는 객체
- ViewResolver: Contoller의 처리 결과를 출력할 View를 결정. View 객체 생성
- View: Controller의 처리 결과를 출력할 화면 정의
Spring MVC 요청 처리 흐름
- Controller와 출력 화면은 개발자가 직접 구현하고 스프링 빈으로 등록해야 함
- DispatcherServlet은 모든 연결을 담당
- 브라우저로부터 요청이 들어오면 요청을 처리하기 위한 컨트롤러 객체를 검색
- 단, 직접 검색이 아닌 HandlerMapping이라는 빈 객체에 컨트롤러 검색을 요청
- HandlerMapping은 클라이언트의 요청 경로를 이용해서 이를 처리할 컨트롤러 빈 객체를 DispatcherServlet에 전달
- ex. 웹 요청 경로가 '/hello'라면 등록된 컨트롤러 빈 중에서 '/hello'요청 경로를 처리할 컨트롤러를 리턴
- DispatcherServlet은 HandlerMapping이 찾아준 컨트롤러 객체를 처리할 수 있는 HandlerAdapter 빈에게 요청 처리를 위임
- HandlerAdapter 빈은 @Controller, Controller 인터페이스, HttpRequestHandler 인터페이스를 동일한 방식으로 처리하기 위해 중간에 사용되는 것
- HandlerAdapter는 컨트롤러의 알맞은 메소드를 호출해서 요청을 처리하고 그 결과를 DispatcherServlet에 리턴
- 이때 HandlerAdpater는 컨트롤러의 처리 결과를 ModelAndView라는 객체로 변환해서 리턴
- HandlerAdapter로부터 컨트롤러의 요청 결과를 ModelAndView로 받으면 DispatcherServlet은 결과를 보여줄 뷰를 찾기 위해 ViewResolver 빈 객체를 사용
- ModelAndView는 컨트롤러가 리턴한 뷰 이름을 담고 있는데 ViewResolver는 이 뷰 이름에 해당하는 View 객체를 찾거나 생성해서 리턴
- 응답을 생성하기 위해 JSP를 사용하는 ViewResolver는 매번 새로운 View 객체를 생성해서 DispatcherServlet에 리턴
- DispatcherServlet은 ViewResolver가 리턴한 View 객체에게 응답 결과 생성을 요청
- JSP를 사용하는 경우 View 객체는 JSP를 실행함으로써 웹 브라우저에게 전송할 응답 결과를 생성
기본 설정
Step1: DispatcherServlet 설정
- Client로부터 request를 전달받는 servlet 객체 (front contoller)
- Web application 설정 파일 (WEB-INF/web.xml)에 설정
- 내부적으로 Spring container(WebApplicationContext)를 생성
<web-app ... >
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
<!-- <url-pattern>*.do</url-pattern> -->
</servlet-mapping>
…
</web-app>
- 3행: dispatcherServlet 이름
- 8행: JSP를 제외한 모든 request들을 처리
- 9행: URL이 .do로 끝나는 request들을 처리
Step2: HandlerMapping 설정
- Request를 처리할 handler (controller 및 method) 선택
- 일반적으로 Spring에서 제공되는 구현 클래스를 이용
- o.s.web.servlet.handler.BeanNameUrlHandlerMapping
- o.s.web.servlet.handler.RequestMappingHandlerMapping
- DispatcherServlet이 사용하는 Spring 설정 파일에 bean 등록
<beans>
<bean id="defaultHandlerMapping"
class="o.s.web.servlet.handler.BeanNameUrlHandlerMapping" />
<bean id="handlerMapping"
class="o.s.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
...
</beans>
- 5행: annotation 기반 handler mapping. <bean> 설정 대신 <mvc:annotation-driven /> 이용 가능
Step3: Controller 구현 및 설정
- Annotation 기반 controller
- Spring에서 제공되는 인터페이스나 클래스를 이용하지 않고 POJO 클래스로 정의
- @Controller annotation을 클래스에 적용 (자동 bean scan 대상)
- @RequestMapping annotation을 이용해서 사용자 정의 메소드를 특정 request URL에 대한 handler method로 지정
package com.example.helloworld.web;
import java.util.Calendar;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping("/hello.do")
public ModelAndView hello() {
@RequestParam(value="name", required=false) String name) {
String message = getGreeting() + name; // request 처리
ModelAndView mav = new ModelAndView("hello"); // view 이름: "hello"
mav.addObject("greeting", message); // model 객체 이름: “greeting”
return mav;
}
private String getGreeting() { // business method
int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
if (hour >= 6 && hour <= 11) {
return "Good morning!";
} else if (hour > 11 && hour <= 14) {
return "Did you have lunch?";
} else if (hour > 14 && hour <= 18) {
return "Good afternoon!";
} else if (hour > 18 && hour <= 24) {
return "Good evening!";
}
return "Hello!";
}
}
- Spring 설정 파일 (dispatcher-servlet.xml)
- 패키지에 있는 @Controller 적용 클래스의 객체를 Spring bean으로 자동 생성
<context:component-scan base-package=“com.example.helloworld.web”/>
Step4: ViewResolver 설정
- 논리적인 view 이름에 대해 물리적인 view 객체 생성
- 일반적으로 Spring에서 제공되는 구현 클래스 이용
- o.s.web.servlet.view.InternalResourceViewResolver
- Spring 설정 파일에 bean으로 등록
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" values="org.springframework.web.servlet.view.JstlView">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
- 1행: view 이름에 prefix와 suffix를 붙여 물리적인 view로 사용할 대상 결정
- "hello" → "/WEB-INF/view/hello.jsp"
Step5: View 구현
- JSP 등을 사용하여 View page 작성
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>인사</title>
</head>
<body>
인사말: <b>${greeting}</b>
</body>
</html>
- 9행: HelloController에서 ModelAndView 객체에 저장한 모델 객체 참조 (이름: "greeting"). 모델 객체는 HttpServletRequest 객체의 속성을 통해 JSP page에 전달되고 참조됨
Spring 설정 파일 (disparcher-servlet.xml)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd ...">
<context:component-scan base-package="com.example.helloworld.web"/>
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 7행: 패키지 내의 controller 객체들을 bean으로 등록
- 8행: annotation 기반 HandlerMapping 객체 생성
- 9행: ViewResolver 객체 생성
Java code 기반 설정 방법
Java Config 클래스를 이용한 설정
- @ComponentScan
- @Controller가 적용된 클래스에 대해 자동 bean 생성
- @EnableWebMvc
- SpringMVC 기본 설정 수행: RequestMappingHandlerMapping, RequestMappingHandlerAdapter 등 필요 한 bean 생성
@Configuration // JavaConfig
@EnableWebMvc // HandlerMapping 등 MVC 구조에 필요한 기본 객체들 생성
@ComponentScan(basePackages={"com.example.helloworld.web"})
public class MvcConfig {
...
}
동일
<beans ...>
<context:component-scan base-package="com.example.helloworld.web"/>
<mvc:annotation-driven />
...
</beans>
- Spring MVC의 기본 설정을 변경(customize)하기 위해 WebMvcConfigurer 인터페이스 구현
- 필요한 메소드만 선택적으로 구현
@Configuration
@EnableWebMvc
@ComponentScan(basePackages={"com.example.helloworld.web"})
public class MvcConfig implements WebMvcConfigurer {
// View Resolver 설정
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/view/", ".jsp");
}
...
}
- 8행: InternalResourceViewResolver bean을 생성하고 prefix와 suffix 값 설정
DispatcherServlet 설정 (web.xml)
- contextClass, contextConfigLocation init-parameter 설정
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.example.helloworld.config.MvcConfig
</param-value>
</init-param>
</servlet>
<servlet-mapping> … </servlet-mapping>
- 7행: JavaConfig class를 이용하는 container
- 13행: JavaConfig class
'프로그래밍 > Spring' 카테고리의 다른 글
[Spring] Auto-wiring (0) | 2022.04.25 |
---|---|
[Spring] DI - XML 기반 설정 (0) | 2022.04.24 |
[Spring] Spring MVC(1) (0) | 2022.04.17 |
[Spring] Spring DI (0) | 2022.04.01 |