새소식

인기 검색어

개인공부/SPRING

Spring MVC 동작원리

  • -

1. 스프링 MVC 핵심 구성 요소


구성요소 이름  설명 
 DispatcherServlet 클라이언트의 요청을 받아 컨트롤러에게 전달, 컨트롤러가 리턴한 결과값을 View에 전달하여 알맞은 응답을 생성하도록 한다.
HandlerMapping  클라이언트의 요청 URL을 어떤 컨트롤러가 처리할지 결정한다. 
 HandlerAdapter DispatcherServlet의 처리 요청을 변환해서 컨트롤러에게 전달,
그 응답 결과를 DispatcherServlet이 요구하는 형식으로 변환한다. 
 Controller 클라이언트의 요청을 처리한 뒤, 결과를 리턴한다.  
 ModelAndView 컨트롤러가 처리한 결과 정보 및 뷰 선택에 필요한 정보를 담는다. 
ViewResolver  컨트롤러의 처리 결과를 보여줄 뷰를 결정한다. 
View  컨트롤러의 처리 결과 화면을 생성한다. JSP 템플릿 파일등을 이용한다. 

 

MVC2
MVC 프레임워크의 흐름은 다음과 같다.

  1. DispatcherServlet 모든 연결을 담당하며, 웹 브라우저로부터 요청을 받음
    • 요청이 들어오면 DispathcerServlet는 HandlerMapping Bean 객체에게 컨트롤러 검색을 요청
    • HandlerMapping은 클라이언트의 요청 경로를 이용해 컨트롤러 Bean객체를 DispathcerServlet에게 전달
  2. DispathcerServlet은 전달받은 객체를 처리할 수 있는 HandlerAdapter Bean에게 요청 처리를 위임
  3. HandlerAdapter는 컨트롤러의 알맞은 메서드를 호출해 요청을 처리
  4. 그 후, 결과를 ModelAndView라는 객체로 DispathcerServlet에게 반환
    • DispathcerServlet는 전달받은 결과를 보여줄 뷰를 찾기 위해 ViewResolver Bean 객체를 사용
    • ViewResolver는 ModelAndView 내부에 있는 뷰 이름에 해당하는 View 객체를 찾거나 생성후 리턴
  5. DispathcerServlet는 VeiwResolver가 리턴한 View 객체에게 응답 결과 생성을 요청

1-1. 컨트롤러와 핸들러

  • 클라이언트의 요청을 실제로 처리하는 것은 컨트롤러
  • DispathcerServlet는 클라이언트의 요청을 전달받는 창구 역할
  • HandlerMapping은 특정 요청 경로를 처리해주는 핸들러를 찾아주는 역할
  • HandlerAdapter는 핸들러의 처리결과를 ModelAndView 객체로 변환하여 DispathcerServlet에게 전달

2. @Controller를 위한 HandlerMapping과 HandlerAdapter


// ControllerConfig.java
@Configuration
@EnableWebMvc
public class MvcConfig{
    ...
}
  • @EnableWebMvc 어노테이션을 통해 HandlerMapping이나 HandleAdapter 설정을 자동으로 추가
// HelloController.java
@Controller
public class HelloController {

    @GetMapping("/hello")
    public String hello(Model model,
            @RequestParam(value = "name", required = false) String name) 
        {
        model.addAttribute("greeting", "안녕하세요, " + name);
        return "hello";
    }
}
  • @EnableWebMvc 어노테이션은 @Controller 타입의 핸들러 객체를 처리하기 위한 클래스를 포함
  • 그중 하나가 RequestMappingHandlerMapping이며,
    이 어노테이션은 @GetMapping 어노테이션 값을 이용해서 웹 브라우저의 요청을 처리할 컨트롤러 Bean을 찾음
  • 앞선 코드에서 @GetMapping에서 “/hello”라는 요청 경로에 대해 hello() 메서드를 호출
    이때 Model 객체를 생성해 첫 번째 파라미터로, HTTP 요청 파라미터를 두 번째 파라미터로 전달
  • RequestMappingHandlerAdapter는 컨트롤러 메서드 결과 값이 String 타입이면,
    해당 값을 뷰 이름으로 갖는 ModleAndView 객체를 생성해 DispatcherServlet에 리턴위의 예제에서 결국 뷰의 이름은 hello가 된다.

3. JSP를 위한 ViewResolver


  • 컨트롤러 처리 결과를 JSP를 이용해서 생성하기 위해 다음 설정을 사용
  • WebMvcConfigurer 인터페이스에 정의된,
    • configureViewResolvers() 매서드의 파라미터 ViewResolverRegistry의 jsp() 매서드를 이용해 ViewResolver를 설정 가능
    • 내부 클래스를 이용하여 다음과 같이 뷰 이름에 해당하는 객체를 요청
@Bean
public ViewResolver viewResolver(){
    InternalResourceViewResolver vr = new InternalResourceViewResolver();
    vr.setPrefix("/WEB-INF/view/");
    vr.setSurfix(".jsp");
    return vr;
}
  • 앞선 코드의 구성처럼, "prefix + 뷰 이름 " surfix"에 해당하는 경로를 할당
  • DispatcherServlet이 View 생성을 요청하면 InternalResourceViewResolver는 이 JSP 코드를 실행하여 결과 생성
// MvcConfig.java
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
  ...
  @Override
  public void configureViewResolvers(ViewResolverRegistry registry) {
      registry.jsp("/WEB-INF/view/", ".jsp"); // 접두사, 접미사 설정
  }
}

4. 디폴트 핸들러와 HandlerMapping의 우선순위


  • web.xml 파일을 참조하면, DispatcherServlet에 대한 매핑 경로가 다음과 같이 '/'로 설정
  • 매핑 경로가 ‘/’인 경우. jsp로 끝나는 요청을 제외한 모든 요청을 DispatcherServlet이 처리
  • 하지만 앞선 코드에서처럼 HandlerMapping으로 @GetMapping(“/hello”) 설정을 사용하였다면, /hello 경로만 처리 가능하므로 “/index.html”등의 요청을 처리할 컨트롤러를 찾을 수 없음
  • 이러한 경로를 처리하기 위한 컨트롤러 객체를 직접 구현할 수도 있지만 다음과 같이,
    WebMvcConfigurer의 configureDefaultServletHandling() 매서드를 사용하는 것이 편리
    // MvcConfig.java
    @Configuration
    @EnableWebMvc
    public class MvcConfig implements WebMvcConfigurer {
    
      @Override
      public void configureDefaultServletHandling
          (DefaultServletHandlerConfigurer configurer) 
      {
          configurer.enable();
      }
      ...
  • 위 설정에서 enable() 매서드는 다음의 두 Bean 객체를 추가
    • DefaultServletRequestHandler
    • SimpleUrlHandlerMapping
  • DefaultServletRequestHandler는 클라이언트의 모든 요청을 WAS가 제공하는 디폴트 서블릿에 전달“/index.html”에 대한 처리를 결국 디폴트 서블릿이 처리하도록 만듦
  • 그리고 SimpleUrlHandlerMapping를 이용하여 모든 경로(“/**“)를 DefaultServletHttp RequestHandler를 이용해 처리하도록 함
  • @EnableWebMvc 어노테이션이 등록하는 HandlerMapping의 적용 우선순위가 enable() 매서드가 등록하는 디폴트 핸들러보다 높음
  • 따라서 다음과 같은 방식으로 요청을 처리
    1. RequestMappingHandlerMapping을 사용해 요청 처리할 핸들러 검색
      • 존재하면 해당 컨트롤러를 이용해 요청을 처리
    2. 존재하지 않으면 SimpleUrlHandlerMapping을 사용해 요청을 처리할 핸들러 검색
      • 모든 경로에 대해 DefaultServletHttpRequestHandler를 리턴
      • DispatcherServlet은 DefaultServletHttpRequestHandler에 처리를 요청
      • DefaultServletHttpRequestHandler는 디폴트 서블릿에 처리를 위임예를 들어 “/index.html” 경로로 요청이 들어오면, 1 과정에서 해당하는 경로를 찾지 못하므로,
        2 과정을 통해 디폴트 서블릿이 /index.html 요청을 처리하게 됨
<!-- web.xml -->
<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>
종류 URL pattern 매칭 URL
1. exact(정확한) mapping /login/hello.do http://localhost/login/hello.do
2. path(경로) mapping /login/* http://localhost/login/
http://localhost/login/hello
http://localhost/login/hello.do
http://localhost/login/test/
3. extension(확장자) mapping *.do http://localhost/hi.do
http://localhost/login/hello.do
4. default mapping / http://localhost/
http://localhost/hello.do
http://localhost/login/
http://localhost/login/hello
http://localhost/login/hello.do

참조 URL

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.