스프링/스프링 MVC 패턴

핸들러 어댑터

chanhee01 2023. 2. 12. 13:46

핸들러 어댑터란 여러 핸들러를 설정하고 그 중 하나를 선택해야 할 상황이 있을 때 핸들러를 매핑해줄 수 있는 장치이다.

public interface MyHandlerAdapter {

    boolean supports(Object handler);

    ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException;
}
핸들러 어댑터 인터페이스를 만들어서 하나의 어댑터로 여러 사이트에 매핑 될 수 있다.
 
public FrontControllerServletV5() {
    initHandlerMappingMap();
    initHandlerAdapters();
}

private void initHandlerAdapters() {
    handlerAdapters.add(new ControllerV3HandlerAdapter());
    handlerAdapters.add(new ControllerV4HandlerAdapter());
}

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

프론트 컨트롤러에서 V3와 V4의 핸들러 어댑터를 추가해준다. 

 

@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 view = viewResolver(viewName);

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

웹 사이트에서 V3에 있는 url로 요청이 오면 V3 핸들러 어댑터로 연결된다.

 

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);
        ModelView mv = controller.process(paramMap);

        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;
    }

V3의 핸들러 어댑터는 위와 같다.

supports 메서드는 핸들러가 V3이면 true를 반환해주고 아니면 실행을 안한다는 메서드이다.

handle 메서드는 V3에 있는 메서드들 중에서 하나를 호출한다는 것이다.

 

 

 

만약에 http:/localhost:8080/front-controller/v5/v3/members으로 접근했다면

public class MemberListControllerV3 implements ControllerV3 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public ModelView process(Map<String, String> paramMap) {
        List<Member> members = memberRepository.findAll();
        ModelView mv = new ModelView("members");
        // members라는 html 파일을 서버에 넘김
        mv.getModel().put("members", members);

        return mv;
    }
}
위의 클래스로 접근 할 것이고, process를 실행해서 members라는 호출해서 사용자가 볼 수 있게 해줄 것이다.
 
반대로 V4를 사용할 경우에는 핸들러 어댑터가 V4에 접근해서 해당하는 클래스들을 실행 할 것이다.
이처럼 핸들러 어댑터는 하나의 인터페이스로 여러 상황에 접근해야할 경우가 있을 때 사용하면 된다.