참고도서
|
1. Spring MVC 핵심 구성 요소
① DispatcherSevlet 은 모든 연결을 담당하며, 웹 브라우저에서 요청이 들어오면
② 그 요청을 처리하기 위해 HandlerMapping 객체에게 컨트롤러 검색을 요청한다.
HandlerMapping은 클라이언트의 요청 경로를 이용해서 이를 처리할 컨트롤러 객체를 찾아서 DispatcherServlet 에 리턴한다.
③ DispatcherServlet 은 @Controller 어노테이션을 이용해서 구현한 컨트롤러, 스프링 2.5까지 사용됐던 Controller 인터페이스를 구현한
컨트롤러, 특수 목적으로 사용되는 HttpRequestHandler 인터페이스를 구현한 클래스를 동일한 방식으로 실행하고 처리하기 위해
HandlerAdapter 객체에게 요청 처리를 위임한다.
④ HandlerAdapter 객체는 컨트롤러의 알맞은 메소드를 호출해서 요청을 처리하고,
⑤ 반환 받은 결과를
⑥ ModelAndView 객체에 담아서 DispatcherServlet 에 리턴한다.
⑦ ModelAndView 객체를 반환 받은 DispatcherServlet 은 ViewResolver 객체를 이용해서 결과를 보여줄 뷰를 검색한다.
ViewResolver 객체는 ModelAndView 객체에 담긴 뷰 이름을 이용해서 View 객체를 찾거나 생성해서 리턴한다.
ViewResolver 는 매번 새로운 View 객체를 생성해서 DispatcherServlet에 리턴한다.
⑧ DispatcherServlet 은 ViewResolver 가 리턴한 View 객체에게 응답 결과 생성을 요청한다.
⑨ JSP를 사용하는 경우, View 객체는 JSP를 실행함으로서 브라우저에게 전송할 응답 결과를 생성한다.
ModelAndView 의 Model 객체에 담겨 있는 데이터가 응답 결과에 필요하면 Model 에서 데이터를 꺼내 JSP 에서 사용할 수 있다.
클라이언트의 요청을 실제로 처리하는 것은 컨트롤러이고,
DispatcherServlet 은 클라이언트의 요청을 전달 받는 창구 역할을 한다.
DispatcherServlet 에게 어떤 컨트롤러가 요청을 처리하는가는 중요하지 않으며,
처리 결과를 ModelAndView 타입의 객체로 전달 받을 수 있기만 하면 된다.
이 때, 사용할 컨트롤러를 찾고, 처리 결과를 ModelAndView 객체로 변환해 주는 객체가 HandlerAdapter 이다.
핸들러 객체의 실제 타입마다 그에 알맞은 HandlerMapping 과 HandlerAdapter 가 존재하기 때문에,
사용할 핸들러의 종류에 따라 해당 HandlerMapping 과 HandlerAdapter 를 스프링 빈으로 등록해 주어야 하는데,
스프링 설정 기능(<mvc:annotaion-driven>)을 사용하면 직접 등록하지 않아도 스프링이 알아서 처리해 준다.
요청을 처리할 컨트롤러를 찾기 때문에 ControllerMapping 이라는 이름이 어울리는데,
스프링 MVC 는 웹 요청을 처리할 수 있는 범용적인 프레임워크를 제공하고 있기 때문에,
클라이언트의 요청을 처리하는 객체가 컨트롤러가 아닐 수도 있다(HttpRequestHandler 등).
그래서 스프링 MVC 는 웹 요청을 실제로 처리하는 객체를 Handler 라고 표현하고 있다.
따라서 컨트롤러는 DispatcherServlet 입장에서 보면 한 종류의 핸들러 객체이다.
2. DispatcherServlet 과 Spring Container
1 2 3 4 5 6 7 8 | <servlet> <!-- WEB-INF/fornt-servlet.xml 을 설정 파일로 이용해서 스프링 컨테이너를 생성 --> <servlet-name>front</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> | cs |
설정 파일을 직접 지정하고 싶으면 contextConfiguration 초기화 파라미터를 설정하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <servlet> <servlet-name>front</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <!-- contextConfiguration 초기화 설정 --> <init-param> <!-- 파라미터 이름으로 contextConfigLocation 사용--> <param-name>contextConfigLocation</param-name> <!-- 파라미터 값으로 사용할 설정파일을 지정 --> <param-value> classpath:spring-mvc.xml classpath:spring-controller.xml <load-on-startup>1</load-on-startup> </servlet> | cs |
HandlerMapping, HandlerAdapter, 컨트롤러, ViewResolver 등의 객체는
DisptacherServlet 이 생성하는 스프링 컨테이너로 부터 구하기 때문에,
DistacherServlet 이 사용하는 설정 파일에 이들 객체를 빈 으로 설정해야 한다.
DispatcherServlet => 설정 파일 로딩 => 스프링 컨테이너 생성
=> 스프링 컨테이너 안에 빈으로 설정된 HandlerMapping, HandlerAdapter, 컨트롤러, ViewResolver 객체 이용
그리고 이렇게 생성되는 스프링 컨테이너는 WebApplicationContext 컨테이너이다.
3. @Controller 를 위한 HandlerMapping 과 HandlerAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /* public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping { } @Controller 타입의 핸들러 객체 처리를 위한 HandlerMapping 클래스인 RequestMappingHandlerMapping 클래스는 @Controller 어노테이션이 적용된 객체의 @RequestMapping 값을 이용해서 웹 브라우저의 요청을 처리할 컨트롤러 빈을 찾는다 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { } RequestMappingHandlerAdapter 클래스는 웹 브라우저로부터 요청된 경로와 @RequestMapping 에 설정된 경로가 일치하는 메소드를 호출한다. 이 때 Model 객체를 생성해서 메소드의 첫 번째 파라미터로 전달한다. 메소드의 리턴 값이 String 타입인 경우, 해당 값을 뷰 이름으로 갖는 ModelAndView 객체를 생성해서 Model 에 담긴 데이터와 View 정보를 DispatcherServlet 에 리턴한다. */ // RequestMappingHandlerMapping 가 @Controller 가 붙은 객체의 // @RequestMapping 값을 이용해서 웹 브라우저의 요청을 처리할 컨트롤러 빈을 찾아낸다 @Controller public class HelloController { // 웹 브라우저로부터의 요청이 /hello 이면 //RequestMappingHandlerAdapter 가 hello() 메소드를 호출, 첫 번째 파라미터로 Model 객체 전달 @RequestMapping("/hello") public String hello(Model model, @RequestParam(value="name", required=false) String name){ // Model 객체에 greeting 이라는 속성 이름으로 속성 값 "안녕하세요, "+name 을 담는다 model.addAttribute("greeting", "안녕하세요, "+name); // View 정보를 View 객체에 담고, // Model 에 담긴 데이터와 View 정보를 ModelAndView 객체에 담아서 return "hello"; } } | cs |
4. JSP 를 위한 ViewResolver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <mvc:view-resolver> <mvc:jsp prefix="/WEB-INF/view/" /> </mvc:view-resolver> <!-- <mvc:jsp> 태그는 public class InternalResourceViewResolver extends UrlBasedViewResolver {} 클래스를 빈 으로 등록한다 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view/" /> <property name="suffix" value=".jsp" /> </bean> <mvc:resolver> 태그는 스프링 4.1 부터 지원하기 때문에, 하위 버전을 사용하는 경우는 직접 InternalResolverViewResolver 클래스를 빈 등록 해야 한다. --> <!-- 컨트롤러의 실행 결과를 받은 DispatcherServlet 은 ViewResolver 에게 뷰 이름에 해당하는 View 객체를 요청한다. 이 때 InternalResourceViewResolver 빈 객체에 의해 prefix + 뷰 이름 + suffix 에 해당하는 경로를 뷰 코드로 사용하는 InternalResourceView 타입의 View 객체를 리턴한다. DispatcherServlet 이 InternalResourceView 객체에 응답 생성을 요청하면, InternalResourceView 객체는 경로에 지정한 JSP 코드를 실행해서 응답 결과를 생성한다. DispatcherServlet 이 View 객체에 응답을 요청할 때, Model 에 담긴 값을 View 객체에 Map 형식으로 전달한다. model.addAttribute("greeting", "안녕하세요, "+name); 의 경우 키 => greeting 값 => "안녕하세요, "+name View 객체는 전달 받은 Map 객체에 담긴 값을 이용해서 알맞은 응답 결과를 출력하도록 구현한다. InternalResourceView 의 경우, Map 객체에 담겨 있는 키 값을 request.setAttribute() 를 이용해서 request 의 속성에 저장한다. 그리고 해당 경로의 JSP 를 실행시킨다. Model 속성이 request 객체의 속성을 통해서 전달되기 때문에 JSP 에서는 ${greeting} 을 이용해서 모델에 담긴 값을 사용할 수 있다. --> | cs |
5. Default Handler 와 HandlerMapping 의 우선 순위
1 2 3 4 5 | <servlet-mapping> <servlet-name>dispatcher</servlet-name> <!-- 서블릿 매핑 경로가 '/' --> <url-pattern>/<url-pattern> </servlet-mapping> | cs |
서블릿 매핑 경로가 '/' 인 경우 .jsp 로 끝나는 요청을 제외한 모든 요청을 DispatcherServlet 이 처리한다.
즉, /index.html 이나 /css/bootstrap.css 와 같은 요청을 DispatcherServlet 이 처리하는 것이다.
그런데, <mvc:annotaiton-driven> 태그를 통해서 등록되는 HandlerMapping은 @Controller 어노테이션이 적용된
빈 객체가 처리할 수 있는 요청 경로만 대응할 수 있다.
@RequestMapping("/hello") => /hello 경로만 처리할 수 있음
따라서, /index.html 이나 /css/bootstrap.css 같은 요청을 처리할 수 있는 컨트롤러 객체를 찾지 못해
DispatcherServlet 은 404 응답을 전송한다.
이런 요청을 처리하기 위해서는 <mvc:default-servlet-handler /> 를 등록하면 된다.
1 2 3 4 5 6 7 8 | <mvc:annotation-driven /> <mvc:default-servlet-handler /> <!-- <mvc:default-servlet-handler /> 가 생성하는 빈 객체 DefaultServletHttpRequestHandler SimpleUrlHandlerMapping --> | cs |
DefaultServletHttpRequestHandler 는 클라이언트의 모든 요청을 WAS 가 제공하는 기본 서블릿에 전달한다.
/index.html 대한 처리를 DefaultServletHttpRequestHandler 에 요청하면,
이 요청을 다시 기본 서블릿에 전달해서 처리하게 한다.
그리고 SimpleUrlHandlerMapping 을 이용해서 모든 경로("/**")를 DefaultServletHttpRequestHandler 를 이용해서 처리하게 설정한다.
<mvc:annotation-driven> 태그가 등록하는 RequestMappingHandlerMapping 의 적용 우선 순위가
<mvc:default-servlet-handler> 태그가 등록하는 SimpleUrlHandlerMapping 의 우선 순위보다 높기 때문에,
웹 브라우저의 요청이 들어오면 DispatcherServlet 은
① RequestMappingHandlerMapping 을 사용해서 요청을 처리할 핸들러를 검색한다.
a. 존재하면 해당 컨트롤러를 이용해서 요청을 처리한다.
② 존재하지 않으면 SimpleUrlHandlerMapping 을 사용해서 요청을 처리할 핸들러를 검색한다.
a. <mvc:default-servlet-handler> 가 등록한 SimpleUrlHandlerMapping 은 모든 경로("/**")에 대해
DefaultServletHttpRequestHandler를 리턴한다.
b. DispatcherServlet 은 DefaultServletHttpRequestHandler 에 처리를 요청한다.
c. DefaultServletHttpRequestHandler 는 디폴트 서블릿에 처리를 위임한다.
의 방식으로 요청을 처리한다.
그리고, <mvc:default-servlet-handler> 태그가 등록하는 SimpleUrlHandlerMapping 의 우선 순위가 가장 낮기 때문에,
별도로 설정하지 않은 모든 요청 경로를 디폴트 서블릿이 처리하게 된다.
'Programming > Spring' 카테고리의 다른 글
Spring MVC (커맨드 객체, 모델) (0) | 2017.08.25 |
---|---|
Spring MVC (요청 매핑, 리다이렉트) (0) | 2017.08.24 |
Spring MVC 기본 설정 (0) | 2017.08.23 |
Spring JdbcTemplate Transaction (0) | 2017.08.22 |
Spring JdbcTemplate Method (0) | 2017.08.22 |
댓글