스프링/3. 스프링 MVC

29. 어댑터 패턴

sdafdq 2023. 8. 7. 22:19
@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());

        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 initHandlerAdapters(List<MyHandlerAdapter> handlerAdapters){
        handlerAdapters.add(new ControllerV3HandlerAdapter());
        handlerAdapters.add(new ControllerV4HandlerAdapter());
    }
//    complete init //
}

먼저랑 비슷한데, 조금만 바뀌었다.

initHandlerMappingMap 부분이랑 initHandlerAdapters 부분이다.

이제 이걸 나중에 밖으로 주입받게끔 (뭐 예를들어 아예 밖에서 Map<>이나 List<>로 만들어서 넣어주거나) 하면 그게 우리가 했던 Spring MVC랑 비슷한 구조이다. Spring Bean에서 등록했듯이. 

아마 우리가 빈에 등록해두면 그게 Bean이름, 그리고 싱글톤으로, 주입 메커니즘 등 객체 뿐만 아니라 여러 정보를 포함한 Spring Bean이 씌어진 객체가 등록되었을 거다. 

 

 

public class ControllerV4HandlerAdapter implements MyHandlerAdapter {
    @Override
    public boolean supports(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, Object>();
        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;
    }
}

여기서 어댑터의 진가가 제대로 나온다.

원래 V4는 ModelView를 반환하지 않았다. 근데 내가 직접 만들어, V4의 정보들과 내가 만든 ModelView와 엮어 반환시키게끔 해줬다.

서로를 엮어 반환시켜 준다, 이게 어댑터 패턴의 핵심이다.

 

이렇게 해두면 굉장히 무한한 확장이 가능해진다.

 

또 앞서 말했던 외부에서 주입해주면 OCP, Open Close Principle이 굉장히 잘 지켜진다(확장엔 열려있고, 수정엔 닫혀있는.)

'스프링 > 3. 스프링 MVC' 카테고리의 다른 글

31. 스프링 MVC 구조  (0) 2023.08.09
30. 어댑터 패턴 정리  (0) 2023.08.07
28. 유연한 컨트롤러  (0) 2023.08.07
27. 단순화  (0) 2023.08.06
26. 모델 추가  (0) 2023.08.06