본문 바로가기

spring

Front Controller (5-1)

이제 앞서 만든 V5 버전에 어댑터에 V3만 넣엇다면 이번에 V4버전을 넣어보자. 이때 어댑터의 진가가 보인다. 

이유는 V3와 V4의 방식은 각 컨트롤러의 process메서드가 사용될때 V3에서는 paramMap만 이용이 되었지만 V4에서는 paramMap와 model 두가지가 사용이 되어 조금의 사용법이 다르지만 이 문제를 어댑터를 통해 극복이 가능하다.

먼저 FrontControllerServletV5에 V4를 넣어주자.

@WebServlet(name="frontControllerServletV5", urlPatterns = "/front-controller/v5/*")
public class FrontControllerServletV5 extends HttpServlet {

    //private Map<String, ControllerV4> controllerMap = new HashMap<>(); 기존의 방식 하나의 방식만 사용이 가능.
    private final Map<String ,Object> handlerMappingMap = new HashMap<>();
    private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();

    public FrontControllerServletV5(){
        initHandlerMappingMap();
        initHandlerAdapter();
    }
    private void initHandlerMappingMap() {
        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());
        handlerMappingMap.put("/front-controller/v5/v4/members/new-form",new MemberFormControllerV4());
        handlerMappingMap.put("/front-controller/v5/v4/members/save",new MemberSaveControllerV4());
        handlerMappingMap.put("/front-controller/v5/v4/members",new MemberListControllerV4());
    }
    private void initHandlerAdapter() {

        handlerAdapters.add(new ControllerV4HandlerAdapter());
        handlerAdapters.add(new ControllerV3HandlerAdapter());
    }

    @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);

        String viewName = mv.getViewName();
        MyView myView =viewResolver(viewName);

        myView.render(mv.getModel(),request,response);
    }

    private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if (adapter.supportBoolean(handler)) {
                return adapter;
            }
        }
        throw new IllegalArgumentException("handler Adapter를 찾지 못햇습니다." + handler);
    }

    private Object getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        return handlerMappingMap.get(requestURI); // 해당 키 값의 value 추출
    }
    private static MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }

    private static Map<String, String> createParaaMap(HttpServletRequest request) {
        Map<String ,String > paramMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName->paramMap.put(paramName, request.getParameter(paramName)));
        return paramMap;
    }
}

이전 코드와 비교해서 보면 별 차이가 없어보이지만 상단쪽에 보면 HandlerMappingMap과 HandlerAdapter에 V4가 추가가 된 모습이 있다. 그 아래부터는 단순히 어댑터가 잇는지 확인하고 어댑터를 연결하고 해당 컨트롤러를 사요하는 방식이라 달라질게 없다. 이제 V4 어댑터를 만들어보자.

public class ControllerV4HandlerAdapter implements MyHandlerAdapter {
    @Override
    public boolean supportBoolean(Object handler) {return (handler instanceof ControllerV4);}

    @Override
    public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        ControllerV4 controller = (ControllerV4) handler;
        Map<String,String> paramMap = createParamMap(request);
        Map<String ,Object >model = new HashMap<>();
        String viewName = controller.process(paramMap,model);
        ModelView mv = new ModelView(viewName);
        mv.setModel(model);
        return mv;
    }
    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;
    }
}

이것 역시 V3HandlerAdapter와 큰 차이가 없다. 하지만 앞서 말했듯이 두 버전의 차이는 process를 호출하는 방식에 차이가 잇으므로 이번에 V4방식에서는 model을 만들고 새로운 ModelView를 만들어 V3와 같은 방식으로 반환을 했다는 점이다. 이렇게 되면 기능은 다른방식으로 실행이 되었지만 결국 반환하는 모습은 같다는걸 알 수 있다.

이것이 바로 핸들러 어댑터의 강점이라고 할 수 있다.

V4는 단순히 viewName만을 반환했지만 어댑터는 ModelView를 이용해 반환을 해야하므로 형식만 바꿔줌으로 인해서 하나의 어댑터 컨트롤러를 통해 형식이 다른 두버전을 동시에 사용이 가능하다는 것이다. 

'spring' 카테고리의 다른 글

SPRING MVC 구조  (0) 2023.03.20
Front-Controller 정리  (0) 2023.03.19
Front Controller (5)  (0) 2023.03.19
Front Controller (4)  (0) 2023.03.19
Front Controller (3)  (0) 2023.03.18