10장의 키워드
#DispatcherServlet
#HandlerMapping
#HandlerAdapter
#ViewResolver
<순서>
Controller를 찾아주는 객체는 왜 HandlerMapping일까?
클라이언트 요청 처리 방법이 @Controller 애노테이션을 붙인 클래스를 이용하는 것과, 자신이 직접 만든 클래스를 이용하는 것 두 가지가 있기 때문이다.
즉, DispatcherServlet은 클라이언트 요청을 처리하는 객체의 타입이 반드시 @Controller를 적용할 클래스일 필요가 없기 때문에 MVC는 웹 요청을 실제로 처리하는 객체를 핸들러(Handler)라고 표현한다.
@Controller 적용 객체나 Controller 인터페이스를 구현한 객체는 모두 스프링 MVC 입장에서 핸들러가 된다.
핸들러 객체의 실제 타입마다 그에 알맞은 HandlerMappging과 HandlerAdapter가 존재하기 때문에, 사용할 핸들러의 종류에 따라 해당 HandlerMapping과 HandlerAdapter를 스프링 빈으로 등록해야 한다.
9장의 web.xml 파일을 보면 DispatcherServlet의 contextConfiguration 초기화 파라미터를 이용해 스프링 설정 클래스 목록을 전달했다.
<servlet>
<!--DispatcherServlet을 dispatcher라는 이름으로 등록-->
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!--contextClass 초기화 파라미터 설정.-->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!--contextConfiguration 초기화 파라미터 값 지정. 파라미터로는 스프링 설정 클래스 목록을 지정-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
config.MvcConfig
config.ControllerConfig
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
DispatcherSevlet은 전달받은 설정 파일을 이용해서 스프링 컨테이너를 생성한다.
HandlerMapping, HandlerAdapter, 컨트롤러, ViewResovler 등의 빈은 이 스프링 컨테이너에서 구하기 때문에,
DispatcherServlet이 사용하는 설정 파일에 빈에 대한 정의가 포함되어야한다.
DispatcherServlet은 웹 브라우저의 요청을 처리할 핸들러 객체를 찾기 위해 HandlerMapping을 사용하고,
찾은 핸들러를 실행하기 위해 HandlerAdapter를 사용하므로 두 빈이 스프링 설정에 등록되어 있어야 한다.
그러나 9장에서 작성한 예제(스프링 설정 파일)에서는 @EnableWebMvc 애노테이션만 추가했다.
@EnableWebMvc의 역할?
@EnableWebMvc는 매우 다양한 스프링 빈 설정을 추가해준다.
이 태그가 빈으로 추가해주는 클래스 중에는 @Controller 타입의 핸들러 객체를 처리하기 위한 다음의 두 클래스가 포함되어 있다.
RequestMappingHandlerMapping은 @Controller가 적용된 객체의 요청 매핑 애노테이션(@GetMapping) 값을 이용해서 웹 브라우저의 요청을 처리할 컨트롤러 빈을 찾는다.
RequestMappingHandlerAdpater은 컨트롤러의 메서드를 알맞게 실행하고
그 결과를 ModelAndView 객체로 변환해서 DispatcherServlet에 리턴한다.
// 9장 HelloController 클래스
@Controller // 스프링 MVC에서 컨트롤러로 사용
public class HelloController {
@RequestMapping("/hello") // "/hello" 요청 경로에 대해 hello() 메서드를 호출
// Model 파라미터는 컨트롤러의 처리 결과를 뷰에 전달할 때 사용
public String hello(Model model,
@RequestParam(value = "name", required = false) String name) { // HTTP 요청 파라미터의 값을 메서드의 두번째 파라미터로 전달
model.addAttribute("greeting", "안녕하세요, " + name);
return "hello"; // 컨트롤러의 처리 결과를 보여줄 뷰 이름으로 "hello" 사용
}
}
컨트롤러 메서드 결과 값이 String이면 해당 값을 뷰 이름으로 갖는 ModelAndView 객체를 생성해서 DispatcherServlet에 리턴하며 Model 객체에 보관된 값도 ModelAndView에 함께 전달한다.
@EnableWebMvc을 사용하면 WebMvcConfigurer 타입의 빈을 이용해 MVC 설정을 추가로 생성한다.
// 스프링 설정 파일
@Configuration // 컨테이너에 빈으로 등록된다.
@EnableWebMvc // 스프링 MVC 설정을 활성화하는 애노테이션. 스프링 MVC를 사용하는데 필요한 다양한 설정을 생성
public class MvcConfig implements WebMvcConfigurer { // MvcConfig 클래스는 WebMvcConfigurer 타입의 빈이 된다.
// DispatcherServlet의 매핑 경로를 '/'로 주었을때, JSP/HTML/CSS 등을 올바르게 처리하기 위한 설정 추가
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// JSP를 이용해 컨트롤러의 실행 결과를 보여주기 위한 설정 추가
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/view/", ".jsp");
}
}
@EnableWebMvc 애노테이션을 사용하면 WebMvcConfigurer 타입인 빈 객체의 메서드를 호출해서 MVC 설정을 추가한다.
ex. configureViewResolvers() 메서드 : ViewResolver설정을 추가한다.
즉, 각각의 메서드가 MVC 설정을 추가한다!!!
컨트롤러 처리 결과를 JSP를 이용해서 생성하기 위해 다음 설정을 사용한다.
// 스프링 설정 파일
@Configuration // 컨테이너에 빈으로 등록된다.
@EnableWebMvc // 스프링 MVC 설정을 활성화하는 애노테이션. 스프링 MVC를 사용하는데 필요한 다양한 설정을 생성
public class MvcConfig implements WebMvcConfigurer { // MvcConfig 클래스는 WebMvcConfigurer 타입의 빈이 된다.
// JSP를 이용해 컨트롤러의 실행 결과를 보여주기 위한 설정 추가
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/view/", ".jsp");
}
}
ViewResolverRegistry의 jsp()메서드를 사용하면 JSP를 위한 ViewResolver를 설정할 수 있다.
위 설정은 org.springframework.web.servlet.view.InternalResourceViewResolver 클래스를 이용해서 다음 설정과 같은 빈을 등록한다.
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResover vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/view/");
vr.setSuffix(".jsp");
return vr;
}
컨트롤러의 실행 결과(by HandlerAdapter)를 받은 DispatcherServlet은 ViewResolver에게 뷰 이름에 해당하는 View 객체를 요청한다.
이때 InterenalResourceViewResolver가 "prefix+뷰이름+suffix"에 해당하는 경로를 뷰 코드로 사용하는 InternalResourceView 타입의 View 객체를 리턴한다.
ex) 뷰 이름 : "hello", 경로 : "/WEB-INF/view/hello.jsp",
리턴 : "/WEB-INF/view/hello.jsp"를 뷰 코드로 사용하는 InternalResourceView 객체
DispatcherServlet은 컨트롤러의 실행 결과를 ModelAndView 형태로 전달받는다. 이때 Model에 담긴 값도 같이 전달되는데, View 객체에 Map 형식으로 전달된다.
@RequestMapping("/hello") // "/hello" 요청 경로에 대해 hello() 메서드를 호출
// Model 파라미터는 컨트롤러의 처리 결과를 뷰에 전달할 때 사용
public String hello(Model model,
@RequestParam(value = "name", required = false) String name) { // HTTP 요청 파라미터의 값을 메서드의 두번째 파라미터로 전달
model.addAttribute("greeting", "안녕하세요, " + name); // Model에 속성을 전달
}
이 경우 DispatcherServlet은 View 객체에 응답 요청할 때 greeting 키를 갖는 Map 객체를 View 객체에 전달한다.
View 객체는 전달받은 Map 객체에 담긴 값을 이용해서 알맞은 응답 결과를 출력한다.
컨트롤러에서 지정한 Model 속성은 request 객체 속성으로 JSP에 전달되기 때문에 JSP는 모델에 지정한 속성 이름을 사용해서 값을 사용할 수 있게 된다. ex) {greeting}
<!--모든 요청을 DispatcherServlet이 처리하도록 서블릿 매핑 설정-->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
9장의 web.xml 설정을 보면 DispatcherServlet에 대한 매핑 경로를 다음과 같이 '/'로 주었다. (url-pattern 태그)
이 경우 .jsp로 끝나는 요청을 제외한 모든 요청을 DispatcherServlet이 처리하게 된다. (ex./index.html, /css/bootstrap.css)
그런데 @EnableWebMvc 애노테이션이 등록하는 HandlerMapping은 @Controller 애노테이션을 적용한 빈 객체가 처리할 수 있는 요청 경로만 대응할 수 있다. ☞ 다른 경로를 처리할 수 있는 컨트롤러 객체를 찾을 수 없다.
따라서 WebMvcConfigurer의 configureDefaultServletHandling()메서드를 사용한다.
// 스프링 설정 파일
@Configuration // 컨테이너에 빈으로 등록된다.
@EnableWebMvc // 스프링 MVC 설정을 활성화하는 애노테이션. 스프링 MVC를 사용하는데 필요한 다양한 설정을 생성
public class MvcConfig implements WebMvcConfigurer { // MvcConfig 클래스는 WebMvcConfigurer 타입의 빈이 된다.
// DispatcherServlet의 매핑 경로를 '/'로 주었을때, JSP/HTML/CSS 등을 올바르게 처리하기 위한 설정 추가
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
DefaultServletHandlerConfigurer의 enable()메서드는 다음의 두 빈 객체를 추가한다.
DefaultServletHttpRequestHandler는 클라이언트의 모든 요청을 WAS(웹 어플리케이션 서버)가 제공하는 디폴트 서블릿에 전달하여 처리하도록 한다.
** WAS 참고
https://codechasseur.tistory.com/25
SimpleUrlHandlerMapping을 이용해서 모든 경로("/**")를 DefaultServletHttpRequestHandler를 이용해서 처리하도록 설정한다.
적용 우선 순위 :
@EnableWebMvc가 등록하는 RequestMappingHandlerMapping > DefaultServletHandlerConfigurer의 enable() 메서드가 등록하는 SimpleUrlHandlerMapping
<DispatcherServlet에 요청을 처리하는 방법>
DefaultServletHandlerConfigurer의 enable()메서드 외에 몇몇 설정도 SimpleUrlHandlerMapping을 등록하는데 enable()이 등록하는 SimpleUrlHandlerMapping의 우선순위가 가장 낮다.
따라서 DefaultServletHandlerConfigurer의 enable()을 설정하면 별도 설정이 없는 모든 요청 경로를 디폴트 서블릿이 처리하게 된다.
문제 1.
다음은 스프링 MVC 프레임워크의 동작 방식이다. 빈칸을 순서대로 채우시오.
답: 1. DispatcherServlet, 2. HandlerMapping, 3. HandlerAdapter, 4. 컨트롤러, 5.ViewResolver, 6. View, 7. JSP
문제 2.
HandlerAdapter는 컨트롤러의 처리 결과를 (ModelAndView)라는 객체로 변환해서 DispatcherServlet에 리턴한다.
문제 3.
DispatcherSevlet은 전달받은 설정 파일을 이용해서 (스프링 컨테이너)를 생성한다.
HandlerMapping, HandlerAdapter, 컨트롤러, ViewResovler 등의 빈은 이 (스프링 컨테이너)에서 구하기 때문에,
DispatcherServlet이 사용하는 설정 파일에 (빈에 대한 정의)가 포함되어야한다.
문제 4.
(@EnableWebMvc)는 매우 다양한 스프링 빈 설정을 추가해준다.
이 태그가 빈으로 추가해주는 클래스 중에는 @Controller 타입의 핸들러 객체를 처리하기 위한 다음의 두 클래스가 포함되어 있다.
문제 5.
컨트롤러의 실행 결과를 받은 DispatcherServlet은 ViewResolver에게 뷰 이름에 해당하는 View 객체를 요청하는데,
이때 InterenalResourceViewResolver가 ("prefix+뷰이름+suffix")에 해당하는 경로를 뷰 코드로 사용하는 (InternalResourceView) 타입의 View 객체를 리턴한다.
문제 6.
매핑 경로가 '/'인 경우, 웹 브라우저의 요청이 들어왔을 때 DispatcherServlet은 먼저 SimpleUrlHandlerMapping을 사용해서 요청을 처리할 핸들러를 검색한다. (O/X)
답: X
코드 문제
문제 1.
@EnableWebMvc을 사용하면 ★타입의 빈을 이용해 MVC 설정을 추가로 생성한다.
// 스프링 설정 파일
@Configuration // 컨테이너에 빈으로 등록된다.
@EnableWebMvc // 스프링 MVC 설정을 활성화하는 애노테이션. 스프링 MVC를 사용하는데 필요한 다양한 설정을 생성
public class MvcConfig implements ★ { // MvcConfig 클래스는 ★ 타입의 빈이 된다.
// DispatcherServlet의 매핑 경로를 '/'로 주었을때, JSP/HTML/CSS 등을 올바르게 처리하기 위한 설정 추가
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// JSP를 이용해 컨트롤러의 실행 결과를 보여주기 위한 설정 추가
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/view/", ".jsp");
}
}
★에 들어갈 것은?
답 : WebMvcConfigurer
문제 2.
ViewResolverRegistry의 jsp()메서드를 사용하면 JSP를 위한 ViewResolver를 설정할 수 있다.
위 설정은 org.springframework.web.servlet.view.♥ 클래스를 이용해서 다음 설정과 같은 빈을 등록한다.
@Bean
public ViewResolver viewResolver() {
♥ vr = new ♥();
vr.setPrefix("/WEB-INF/view/");
vr.setSuffix(".jsp");
return vr;
}
♥에 들어갈 것은?
답 : InternalResourceViewResover
[스프링2] 11장. MVC 1 : 요청, 매핑, 커맨드 객체, 리다이렉트, 폼 태그, 모델 (2) (0) | 2022.12.22 |
---|---|
[스프링2] 11장. MVC 1: 요청 매핑, 커맨드 객체, 리다이렉트, 폼 태그, 모델 (1) (0) | 2022.12.22 |
[스프링2] 9장. 스프링 MVC 시작하기 (0) | 2022.11.24 |
[스프링2] 8장. DB연동 (2) (0) | 2022.11.17 |
[스프링2] 8장. DB 연동 (1) (0) | 2022.11.17 |