Spring/mvc

[Spring MVC 1] - MVC 프레임워크 - 유연한 컨트롤러 2

dev_rosieposie 2022. 8. 31. 23:43

Goal : 어댑터 패턴을 사용해서 프론트 컨트롤러가 다양한 방식의 컨트롤러를 처리할 수 있도록 변경해본다.

유연한 컨트롤러 2

FrontControllerServletV5

hello/servlet/web/frontcontroller/v5/frontControllerServletV5.java

package hello.servlet.web.frontcontroller.v5;

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

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

        //v4 추가
        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() {
        handlerAdapters.add(new ControllerV3HandlerAdapter());
        handlerAdapters.add(new ControllerV4HandlerAdapter());
    }
}
  • 기존 코드와 동일하고 v4만 추가

ControllerV4HandlerAdapter

hello/servlet/web/frontcontroller/v5/adapter/ControllerV4HandlerAdapter.java

package hello.servlet.web.frontcontroller.v5.adapter;

import hello.servlet.web.ModelView;
import hello.servlet.web.frontcontroller.v3.ControllerV3;
import hello.servlet.web.frontcontroller.v4.ControllerV4;
import hello.servlet.web.frontcontroller.v5.MyHandlerAdapter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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);
        HashMap<String, Object> model = new HashMap<>();

        String viewName = controller.process(paramMap, model);

	//model을 adapter에서 생성하고 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;
    }
}
  • 기존 코드와 비슷
  • adapter에서 모델을 생성하고 세팅함

 

http://localhost:8080/front-controller/v5/v4/members/new-form 등록 실행 결과

http://localhost:8080/front-controller/v5/v4/members/members 목록 조회 실행 결과

 

실행로직

ControllerV4 controller = (ControllerV4) handler;

Map<String, String> paramMap = createParamMap(request);
HashMap<String, Object> model = new HashMap<>();

String viewName = controller.process(paramMap, model);

handler를 ControllerV4로 캐스팅하고 paramMap, model을 만들어서 해당 컨트롤러를 호출한다. 그리고 viewname을 반환한다.

 

어댑터 변환

ModelView mv = new ModelView(viewName);
mv.setModel(model);

return mv;

어댑터가 호출하는 ControllerV4는 뷰의 이름을 반환한다. 그런데 어댑터는 뷰의 이름이 아니라 ModelView를 만들어서 반환해야 한다. 여기서 어댑터가 꼭 필요한 이유가 등장하는데 ControllerV4는 뷰의 이름을 반환했지만, 어댑터는 이것을 ModelView로 만들어서 형식을 맞추어 반환한다. 마치 110v 전기 콘센트를 220v 전기 콘센트로 변경하듯!!! 

 

어댑터와 ControllerV4

public interface ControllerV4 {

    String process(Map<String, String> paramMap, Map<String, Object> model);
}
public interface MyHandlerAdapter {

    ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException;
}

**  정리 

매핑정보에서 v3,v4를 가져오고 핸들러 어댑터 목록에서 v3, v4용 어댑터를 찾아서 핸들러 어댑터를 호출해주면,핸들러를 호출하고 실제 핸들러인 컨트롤러를 호출하여 인터페이스에 맞게 모델뷰로 변환해서 반환한다. 그를 프론트 컨트롤러가 사용한다. 프론트 컨트롤러 입장에서는 핸들러 어댑터 인터페이스에 의존하고 구현클래스가 뭐가 되었든 상관이 없다. 마지막으로 뷰리졸버를 호출하여 렌더를 하면 된다.

추후 설정하는 부분만 밖으로 빼서 주입하면 바꾸면 완벽하게 ocp를 지킬 수 있다 -> 기능을 확장하더라도 코드를 변경할 필요가 없다.

 

 

@ 스프링 MVC 1편 - 백엔드 웹개발 by 김영한을 참조하고 있습니다.