스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 16

Spring 정리 2021. 12. 7. 14:01

인프런 강의 34일차.

 - 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 1 (김영한 강사님)

 - 서블릿, JSP, MVC 패턴

 - 서블릿으로 1차 구현

   -> 서블릿으로 구현했을 때 불편한 점 개선을 위해 JSP로 2차 구현

   -> JSP로도 불편한 점을 개선하기 위해 MVC 패턴으로 3차 구현

 

3. 스프링 MVC - 구조 이해

 3.6 핸들러 매핑과 핸들러 어댑터

 - 지금은 전혀 사용하지 않지만, 과거에 주로 사용했던 스프링 제공 컨트롤러로 핸들러 매핑과 어댑터를 이해해보자.

public interface Controller {
    ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse
    response) throws Exception;
}

 - 과거 버전 스프링 컨트롤러

 - 스프링도 처음에는 이런 형태의 컨트롤러를 제공했다.

 - Controller 인터페이스는 @Controller 애노테이션과 전혀 다르다.

 

package hello.servlet.web.springmvc.old;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component("/springmvc/old-controller")
public class OldController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("OldController.handleRequest");      //호출되는지만 확인
        return null;
    }
}

 - hello.servlet.web.springmvc.old.OldController

 - @Component : 이 컨트롤러는 /springmvc/old-controller라는 이름의 스프링빈으로 등록되었다.

 - 빈의 이름으로 URL을 매핑할 것이다.(name, url-pattern이 없다)

 - 실행 : http://localhost:8080/springmvc/old-controller

 - 콘솔에 OldController.handleRequest가 출력되면 성공

 

 - 이 컨트롤러가 호출되려면 다음 2가지가 필요하다.

 - HandlerMapping(핸들러 매핑)

   -> 핸들러 매핑에서 이 컨트롤러를 찾을 수 있어야 한다.

   -> 예) 스프링 빈의 이름(/springmvc/old-controller)으로 핸들러를 찾을 수 있는 핸들러 매핑이 필요하다.

 - HandlerAdapter(핸들러 어댑터)

   -> 핸들러 매핑을 통해서 찾은 핸들러를 실행할 수 있는 핸들러 어댑터가 필요하다.

   -> 예) Controller 인터페이스를 실행할 수 있는 핸들러 어댑터를 찾고 실행해야 한다

 

 - 스프링 부트가 자동 등록하는 핸들러 매핑과 핸들러 어댑터 샘플 (우선순위에 따라 호출된다)

HandlerMapping

0 = RequestMappingHandlerMapping  : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1 = BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 찾는다.

HandlerAdapter

0  = RequestMappingHandlerAdapter  : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1  = HttpRequestHandlerAdapter  : HttpRequestHandler 처리 
2  = SimpleControllerHandlerAdapter : Controller 인터페이스 (애노테이션 X, 과거에 사용)

핸들러 매핑도, 핸들러 어댑터도 모두 순서대로 찾고 만약 없으면 다음 순서로 넘어간다.

 

 - 1. 핸들러 매핑으로 핸들러 조회

   1. HandlerMapping 을 순서대로 실행해서 핸들러를 찾는다.

   2. 이 경우 빈 이름으로 핸들러를 찾아야 하기 때문에 이름 그대로 빈 이름으로 핸들러를 찾아주는 

      BeanNameUrlHandlerMapping 가 실행에 성공하고 핸들러인 OldController를 반환한다.

 

 - 2. 핸들러 어댑터 조회

   1. HandlerAdapter의 supports()를 순서대로 호출한다.

   2. SimpleControllerHandlerAdapter 가 Controller 인터페이스를 지원하므로 대상이된다. 

 

 - 3. 핸들러 어댑터 실행

   1. 디스패처 서블릿이 조회한 SimpleControllerHandlerAdapter를 실행하면서 핸들러 정보도 함께 넘겨준다.

   2. SimpleControllerHandlerAdapter 는 핸들러인 OldController를 내부에서 실행하고 그 결과를 반환한다. 

 

 - OldController 핸들러 매핑, 어댑터 

 - OldController를 실행하면서 사용된 객체는 다음과같다.

  • HandlerMapping = BeanNameUrlHandlerMapping (0번째는 없었고, 1번째가 선택됨)
  • HandlerAdapter = SimpleControllerHandlerAdapter (0, 1번째는 없었고, 2번째가 선택됨)

 3.7 HttpRequestHandler

 - 핸들러 매핑과, 어댑터를 더 잘 이해하기 위해 Controller 인터페이스가 아닌 다른 핸들러를 비교해보자..

 - HttpRequestHandler 핸들러(컨트롤러)는 서블릿과 가장 유사한 형태의 핸들러이다.

public interface HttpRequestHandler {
    void handleRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException;
}

 - HttpRequestHandler

package hello.servlet.web.springmvc.old;

import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component("/springmvc/request-handler")
public class MyHttpRequestHandler implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("MyHttpRequestHandler.handleRequest");
    }
}

 - hello.servlet.web.springmvc.old.MyHttpRequestHandler

 - 실행 : http://localhost:8080/springmvc/request-handler

 - 웹 브라우저에 빈 화면이 나오고, 콘솔에 MyHttpRequestHandler.handleRequest가 출력되면 성공이다.

 

 - 1. 핸들러 매핑으로 핸들러 조회

  1. HandlerMapping 을 순서대로 실행해서 핸들러를 찾는다.

  2. 이 경우 빈 이름으로 핸들러를 찾아야 하기 때문에 이름 그대로 빈 이름으로 핸들러를 찾아주는

     BeanNameUrlHandlerMapping 가 실행에 성공하고 핸들러인 MyHttpRequestHandler를 반환한다.

 

 - 2. 핸들러 어댑터 조회

  1. HandlerAdapter의 supports()를 순서대로 호출한다.

  2. HttpRequestHandlerAdapter 가 Controller 인터페이스를 지원하므로 대상이된다. 

 

 - 3. 핸들러 어댑터 실행

  1. 디스패처 서블릿이 조회한 HttpRequestHandlerAdapter 를 실행하면서 핸들러 정보도 함께 넘겨준다.

  2. HttpRequestHandlerAdapter 는 핸들러인 MyHttpRequestHandler를 내부에서 실행하고 그 결과를 반환한다. 

 

 - MyHttpRequestHandler 핸들러 매핑, 어댑터

 - OldController를 실행하면서 사용된 객체는 다음과같다.

  • HandlerMapping = BeanNameUrlHandlerMapping 
  • HandlerAdapter = HttpRequestHandlerAdapter 

 3.8 @RequestMapping
 - 가장 우선 순위가 높은 핸들러 매핑과 핸들러 어댑터는 
 - RequestMappingHandlerMapping, RequestMappingHandlerAdapter이다. 
   -> @RequestMapping의 앞글자를 따서 만든 이름인데, 이것이 바로 지금 스프링에서 주로 사용하는 애노테이션 기반의 컨트롤러를 지원하는 매핑과 어댑터이다.

   -> 실무에서는 99.9% 이 방식의 컨트롤러를 사용한다.