jiisoo
지수로그
jiisoo
전체 방문자
오늘
어제

블로그 메뉴

  • home
  • Github
  • 알고리즘 문제풀이 저장소
  • 분류 전체보기 (80)
    • Java (1)
    • Spring (30)
    • JPA (15)
    • cs (8)
      • 디자인패턴 (1)
      • 네트워크 (5)
      • Database (1)
      • 운영체제 (1)
    • algorithm (18)
      • 알고리즘 & 자료구조 이론 (12)
      • 알고리즘 풀이 (6)
    • 면접 준비 (0)
    • 회고 (5)
      • ATDD (4)
      • 학습테스트로 배우는 spring 2기 (1)
      • 프로젝트 (0)

인기 글

최근 댓글

최근 글

태그

티스토리

hELLO · Designed By 정상우.
jiisoo

지수로그

[spring] Front Controller (3)
Spring

[spring] Front Controller (3)

2023. 3. 9. 20:12

5단계 - 어댑터 패턴을 적용하기

  • 어댑터 패턴을 적용한 프론트 컨트롤러는 다양한 방식의 컨트롤러를 처리할 수 있다.

V5 구조

  • 핸들러 어댑터는 어댑터의 역할을 하여 다양한 종류의 컨트롤러를 호출할 수 있도록 해준다.
public interface MyHandlerAdapter {

    boolean supports(Object handler);

    ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException;
}
  • 어댑터의 역할은 실제 컨트롤러를 호출하고 ModelView 를 반환해야 한다.
    • 만약 컨트롤러가 반환하지 못할 경우 어댑터가 대신 ModelView 를 직접 생성해서 반환해야 한다.

 

 

1️⃣ 실제 어댑터 구현하기

 

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

        return controller.process(paramMap);
    }

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

 

 

V4 을 지원하는 어댑터

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

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

        return mv;
    }

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

 

 

 

 

2️⃣ 프론트 컨트롤러 리팩토링

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

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

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

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("FrontControllerServletV1.service"); // 실제 테스트 해볼 때에는 로그로 해보는 것이 좋다.

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


    private Object getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        return handlerMappingMap.get(requestURI);// value 값에 들어있는 객체 인스턴스가 반환이 된다.
    }
    private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
        throw new IllegalArgumentException("handler adapter를 찾을 수 없습니다. handler = " + handler);
    }

    private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }
}
  • 이전과 달라진 점이 있다면, 전의 코드에서는 컨트롤러를 직접 매핑해서 사용했지만, 이제는 어댑터를 사용하기 때문에 컨트롤러 뿐만 아니라 어댑터가 지원하는 선에서는 어떤 것이라도 URL 을 매핑해서 사용이 가능하다.

 

 

 

 

<김영한 - '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술'을 참고하였습니다.>

 

 

'Spring' 카테고리의 다른 글

[spring] logging  (0) 2023.03.13
[spring] spring MVC 구조 이해 - dispatcherServlet  (0) 2023.03.12
[spring] Front Controller (2)  (0) 2023.03.08
[spring] Front Controller (1)  (0) 2023.03.07
[spring] MVC 패턴 도입하기  (0) 2023.03.06
    'Spring' 카테고리의 다른 글
    • [spring] logging
    • [spring] spring MVC 구조 이해 - dispatcherServlet
    • [spring] Front Controller (2)
    • [spring] Front Controller (1)
    jiisoo
    jiisoo

    티스토리툴바