Dispatcher Servlet이 스프링 MVC 구조의 핵심이 된다.
<Dispatcher Servlet 코드 구성> (**직접 만든 servlet MVC구조 코드로 복습하면 이해가 잘 됨)
1. 핸들러 조회 : 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.
2. 핸들러 어댑터 조회 : 핸들러를 실행할 수 있는 핸들러 어댑터를 조회
* 어댑터가 필요한 이유? 확장성있는 설계를 위해 => 각기 다른 핸들러(컨트롤러)가 유연하게 동작되게 하려면 어댑터가 끼워져야 함
3. 핸들러 어댑터 실행
4. 핸들러 실행 : 핸들러 어탭터가 핸들러를 실행
5. ModelAndView 반환 : 핸들러 어댑터는 핸들러가 반환하는 정보를 MAV로 변환하여 반환
6. viewResolver 호출 : 뷰 리졸버를 찾고 실행
7. view 반환 : 뷰 리졸버의 역할은 뷰의 논리이름을 물리이름으로 바꾸고 렌더링 역할을 담당하는 뷰 객체를 반환
8. 뷰 렌더링 : 뷰를 통해서 뷰를 렌더링
스프링 MVC의 강점
-핸들러 매핑, 핸들러 어댑터, 뷰 리졸버, 뷰를 모두 인터페이스로 제공하여 확장성 있는 설계를 제공
핸들러 매핑
초기 방식
@Component : "/springmvc/old-controller"이라는 이름의 스프링 빈이 등록되고, 이 빈으로 URL 매핑
@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 new ModelAndView("new-form");
}
}
<예시>
Servlet과 가장 유사한 형태인 HttpRequestHandler를 구현해서 사용해보자.
@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");
}
}
스프링에는 이미 HandlerMapping과 HandlerAdapter가 대부분 구현되어 있다.
스프링은 아래와 같은 순서로 핸들러 매핑, 핸들러 어댑터 조회를 실행한다.
<HandlerMapping>
0 = RequestMappingHandlerMapping : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1 = BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 찾는다.
<HandlerAdapter>
0 = RequestMappingHandlerAdapter : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1 = HttpRequestHandlerAdapter : HttpRequestHandler 처리
2 = SimpleControllerHandlerAdapter : Controller 인터페이스(애노테이션X, 과거에 사용) 처리
과정
1. 핸들러매핑으로 핸들러 조회
: 여기서는 빈 이름으로 핸들러를 찾음. BeanNameUrlHandlerMapping이 실행되고
MyHttpRequestHandler가 반환됨
2. 핸들러 어댑터 조회
HttpRequestHandlerAdapter 가 HttpRequestHandler 인터페이스를 지원하므로 대상이 된다.
3. 핸들러 어댑터 실행
HttpRequestHandlerAdapter가 핸들러인 MyHttpRequestHandler를 내부에서 실행하고 그 결과를 반환해줌
* @RequestMapping
위에서 알 수 있듯이 우선순위가 가장 높은 핸들러 매핑과 핸들러 어댑터는
RequestMappingHandlerMapping, RequestMappingHandlerAdapter 이다.
이 방식이 실무에서는 99.99% 사용됨
뷰 리졸버 이용하기
스프링 부트는 InternalResourceViewResolver 라는 뷰 리졸버를 자동으로 등록하는데,
application.properties에 다음을 추가하면
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
상대 경로만을 이용해서 사용할 수 있다.
스프링 부트가 자동 등록하는 뷰 리졸버
1 = BeanNameViewResolver : 빈 이름으로 뷰를 찾아서 반환한다. (예: 엑셀 파일 생성 기능에 사용)
2 = InternalResourceViewResolver : JSP를 처리할 수 있는 뷰를 반환한다
뷰 리졸버 작동 방식
@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 new ModelAndView("new-form");
}
}
1. 핸들러 어댑터 호출
핸들러 어댑터를 통해 new-form 이라는 논리 뷰 이름을 획득한다.
2. ViewResolver 호출
new-form이라는 뷰 이름으로 viewResolver를 순서대로 호출한다. BeanNameViewResolver는 new-form이라는 이름의 스프링 빈으로 등록된 뷰를 찾아야 하는데 없다. InternalResourceViewResolver가 호출된다.
3. InternalResourceViewResolver
이 뷰 리졸버는 InternalResourceView 를 반환한다.
4. 뷰 - InternalResourceView
InternalResourceView는 JSP처럼 포워드 forward()를 호출해서 처리할 수 있는 경우에 사용한다.
5. view.render()
view.render()가 호출되고 InternalResourceView는 forward()를 사용해서 JSP를 실행한다.
---------------
참고: 인프런 김영한님 강의(스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술)
댓글