김영한님의 스프링 MVC 1편 강의를 듣고 정리한 내용입니다.
initHandlerMappingMap()
에서 직접 목록을 추가initHHandlerAdapters()
에서 직접 목록을 추가servie()
안에서getHandler()
, getHandlerAdapter()
해서 가져온 핸들러로 처리한 결과를 ModelView
로 반환받는다.getViewName()
으로 뷰이름 받아서 MyView 생성render()
안에서 RequestDispather
가 forward()
해준다.// 프론트 서블릿
public class FrontControllerServletV5 extends HttpServlet {
private final Map<String, Object> handlerMappingMap = new HashMap<>();
private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();
private void initHandlerMappingMap() {
handlerMappingMap.put("/front-controller/v5/v3/members/new-form", new MemberFormControllerV3());
handlerMappingMap.put(...);
...
}
private void initHandlerAdapters() {
handlerAdapters.add(new ControllerV3HandlerAdapter());
handlerAdapters.add(...);
...
}
protected void servie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object handler = getHandler(request);
MyHandlerAdapter adapter = getHandlerAdapter(handler);
//실제 처리
ModelView mv = adapter.handle(request, response, handler);
MyView view = viewResolver(mv.getViewName());
// 뷰 렌더링
view.render(mv.getModel(), request, response);
}
}
// 뷰
public class MyView {
public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
dispatcher.forward(request, response);
}
}
initHandlerMappings()
에서 빈을 가져옴initHandlerAdapters()
에서 빈을 가져옴doService()
안에서 doDispatch()
호출doDispatch()
안의 getHandler()
, getHandlerAdapter()
로 받아온 핸들러로 처리한 결과를 ModelAndView로 반환 받음processDispatchResult()
에 인자로 넘기면 그 안에서 render()
render()
안에서 resolvViewname()
으로 View를 받환 받음render()
로 화면을 렌더링// 서블릿
public class DispatcherServlet extends FrameworkServlet {
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
private void initHandlerMappings(ApplicationContext context) {
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(...);
}
private void initHandlerAdapters(ApplicationContext context) {
Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(...);
}
protected void doService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
doDispatch(request, response);
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = null;
mappedHandler = getHandler(processedRequest);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
...
render(mv, request, response);
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
view.render(mv.getModelInternal(), request, response);
}
}
// 뷰
public interface View {
void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
스프링에서 컨트롤러를 호출하려면
HandlerMapping
에서 스프링 빈 이름으로 핸들러(=컨트롤러)를 찾아온다.HandlerAdapter
에서 1번에서 찾은 핸들러를 실행할 수 있는 어댑터를 찾아온다.HandlerMapping
이렇게 해서 찾은 컨트롤러를 핸들러로 가져온다. 그 다음 이 핸들러를 처리할 수 있는 어댑터를 다시 찾아야 한다.
HandlerAdapter
스프링부트가 application.properties
에 있는 설정정보를 가져와서 InternalResourceViewResolver
라는 뷰 리졸버를 자동 등록한다.
// application.properties
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
// DispatcherServlet.properties
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
// InternalResourceViewResolver.java
public class InternalResourceViewResolver extends UrlBasedViewResolver {
public InternalResourceViewResolver(String prefix, String suffix) {
this();
setPrefix(prefix); // -> UrlBasedViewResolver.setPrefix()
setSuffix(suffix); // -> UrlBasedViewResolver.setSuffix()
}
}
// UrlBasedViewResolver.java
public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
public void setPrefix(@Nullable String prefix) {
this.prefix = (prefix != null ? prefix : "");
}
public void setSuffix(@Nullable String suffix) {
this.suffix = (suffix != null ? suffix : "");
}
}
HandlerAdapter로 논리적 이름으로 뷰 리졸버가 호출되면