어댑터 패턴에 관한 것이다.
그러니까, 왜 노트북이나 그런 거 보면 규격에 맞게 전기코드 끝 부분이 다르다. 그러면 우리가 젠더같은 걸 사서 끼워서 노트북같은 제품의 규격에 맞게 해서 끼우기도 하는데, 여기서 젠더같은 걸 어댑터, 라고 한다. 컨트롤러(여기선 핸들러라고 부름)는 원래 전기코드다.
위에서 보면 매핑정보를 확인하고, 핸들러 어댑터에서 맞는 어댑터(젠더)를 가져오고, 그 어댑터와 함께 핸들러(컨트롤러)를 호출한다. 아니, 이제는 어댑터로 컨트롤러를 호출한다.
즉, 요청이 들어오면 핸들러 매핑정보를 찾아서 처리할 수 있는 요청인지 확인하고, 처리할 수 있는 요청이라면 핸들러 어댑터 목록에서 가져온다. 그리고 이 핸들러 어댑터에서 컨트롤러를 호출하고, 이 과정을 거치며 ModelView가 생성되고 거기 안에 데이터가 들어간다.
그냥 처음에는 Controller라는 인터페이스를 만들어서 그걸 V1~V4가 상속받으면 되지 않나 했는데 자바는 인터페이스 상속받으면서 인자를 못바꾼다고 함..
@WebServlet(name = "frontControllerServletV5", urlPatterns = "/front-controller/v5/*")
public class FrontControllerServletV5 extends HttpServlet {
private final Map<String, Object> handlerMappingMap = new HashMap<>();
private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();
public FrontControllerServletV5() {
initHandlerMappingMap(handlerMappingMap);
initHandlerAdapters(handlerAdapters);
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object handler = getHandler(request);
if(handler == null){
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
MyHandlerAdapter adapter = getHandlerAdapter(handler);
ModelView mv = adapter.handle(request, response, handler);
MyView view = viewResolver(mv.getViewName());
view.render(mv.getModel(), request, response);
}
private MyHandlerAdapter getHandlerAdapter(Object handler){
for( MyHandlerAdapter adapter : handlerAdapters){
if(adapter.supports(handler)) return adapter;
}
throw new IllegalArgumentException("handler adapter를 찾을 수 없습니다. handler = " + handler);
}
private Object getHandler(HttpServletRequest request){
return handlerMappingMap.get(request.getRequestURI());
}
public MyView viewResolver(String viewName){
String viewPath = "/WEB-INF/views/" +viewName+".jsp";
return new MyView(viewPath);
}
// init //
private void initHandlerMappingMap(Map<String, Object> handlerMappingMap){
handlerMappingMap.put("/front-controller/v5/v3/members/new-form",new MemberFormControllerV3());
handlerMappingMap.put("/front-controller/v5/v3/members/save",new MemberSaveControllerV3());
handlerMappingMap.put("/front-controller/v5/v3/members",new MemberListControllerV3());
}
private void initHandlerAdapters(List<MyHandlerAdapter> handlerAdapters){
handlerAdapters.add(new ControllerV3HandlerAdapter());
}
// complete init //
}
먼저 맵핑정보, 어댑터 정보를 초기화 해준다.
그 다음 url을 통해 맵에서 핸들러를 얻어온다.
그 다음 얻어온 핸들러를 통해 만약 연결할 수 있는 어댑터가 있다면 어댑터를 얻어오고, 없으면 예외를 던진다.
어댑터를 통해 핸들러를 실행한다. (안의 process()를 실행한다.) 그건 ModelView를 반환해 준다.
거기에는 View에 넘어갈 데이터와 View의 이름에 대한 정보가 담겨져 있다.
viewResolve()를 통해 full path를 넣어준 MyView를 반환해 준다.
MyView.Render() <-dispatcher.forward()이다.
를 통해 jsp를 호출하고 그 jsp가 response에 컨테이너에 의해 담겨 이 모든 service가 끝나면 사용자에게 응답된다.
public interface MyHandlerAdapter {
boolean supports(Object handler);
ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException;
}
public class ControllerV3HandlerAdapter implements MyHandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof ControllerV3;
}
@Override
public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
ControllerV3 controller = (ControllerV3) handler;
Map<String, String> paramMap = createParamMap(request);
return controller.process(paramMap);
}
private static Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
}
}
어댑터로 가능한 핸들러 인지 아닌 지 판별하고, 가능한 거라면 거기에 맞는 어댑터를 반환 시킨다. (맨 위 보면 모두 for문으로 돌린다.)
만약 있다면 그 어댑터로부터 핸들러를 넣어 실행시킨다(컨트롤러의 process()를 실행하고, 그 과정에서 ModelView에 논리이름과 view에 전할 데이터들이 들어가고, 그 ModelView를 반환받는다.). 캐스팅 하고 실행시키면 된다.
그걸 view에 넣고 render()를 호출한다.
'스프링 > 3. 스프링 MVC' 카테고리의 다른 글
30. 어댑터 패턴 정리 (0) | 2023.08.07 |
---|---|
29. 어댑터 패턴 (0) | 2023.08.07 |
27. 단순화 (0) | 2023.08.06 |
26. 모델 추가 (0) | 2023.08.06 |
25. 프론트 컨트롤러 공통로직(뷰 추가) (0) | 2023.08.06 |