Front Controller Pattern

배형만·2022년 1월 28일
0

김영한님의 강의를 듣고 복습차 기록을 남긴다.

스프링을 공부하고는 있었지만 자세한 동작개념과 구조에 대한 지식이 부족하여 Spring이 편리하게 제공해주고 있는 기능들을 직접 구현해보는 과정이다.

이번에 정리를 해보려하는 부분은 Front Controller이다.

다음의 그림을 보자

각 Servlet당 하나의 URL을 부여받고 공통된 로직을 수행후 Controller 로직이 수행하도록 구현되어 있다.

어차피 공통된 로직이니 코드의 반복을 줄이고 좀더 효율적이게 설계할수 없을까? 라는 고민에서 시작된것이 Front Controller Pattern이라고 한다.

아래는 Front Controller Pattern이 적용된 구조의 모습이다.

Front Controller Pattern의 장점은 이러하다.

  • 코드의 중복을 줄일 수 있다.
  • Front Controller Servlet하나로 클라이언트의 요청을 받을수 있다.(즉, Front Controller를 제외한 나머지 Controller는 Servlet을 사용하지 않아도 된다.)
  • Front Controller가 요청에 알맞는 컨트롤러를 찾아서 호출해 준다.

Spring을 공부해본 사람들은 Spring이 들어오는 요청에 따라 요청을 처리해줄수 있는 컨트롤러를 자동으로 찾아준다는 것을 알고 있을것이다.

Front Controller가 제공해 주는 기능과 너무나도 비슷하지 않은가?

다음의 그림을 보자.

기본적으로 Spring은 이러한 아키택쳐를 가지고 있다.

출처 https://server-engineer.tistory.com/253

DispatcherServlet이 요청을 받아 HandlerMapping에 요청 URL과 매핑이 되어 있는 Controller가 있는지 검색한다.

이미 눈치 챘을수 있지만 이 DispathcerServlet이 Front Controller Pattern으로 구현이 되어 있다.

Front Controller에 대해 대략적으로 알아봤으니 코드를 통하여 어떻게 구현이 되어 있는지 살펴보자.

@WebServlet(name = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*")
public class FrontControllerServletV1 extends HttpServlet {

    private Map<String, ControllerV1> controllerMap = new HashMap<>();

    public FrontControllerServletV1() {
        controllerMap.put("/front-controller/v1/members/new-form", new MemberFormControllerV1());
        controllerMap.put("/front-controller/v1/members/save", new MemberSaveControllerV1());
        controllerMap.put("/front-controller/v1/members", new MemberListControllerV1());
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //request.getRequestURI -> contextPath를 제외만 url을 꺼내온다
        String requestURI = request.getRequestURI();
        ControllerV1 controller = controllerMap.get(requestURI);
        if(controller == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        controller.process(request, response);
    }
}

먼저 Front Controller를 담당하는 FrontControllerServletV1.java이다.
처리를 해줄수 있는 URL들을 controllerMap에 저장해준 후 요청이 들어오면 request.getRequestURI()를 통해 URL 검색을 시작한다. 검색에 성공하면 해당 컨트롤러에게 요청을 보내고, 실패시 404에러를 던진다.

public class MemberListControllerV1 implements ControllerV1 {

    private MemberRepository memberRepository = MemberRepository.getInstance();
    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Member> members = memberRepository.findAll();
        request.setAttribute("members", members);
        String viewPath = "/WEB-INF/views/members.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

예시로 컨트롤러 MemberListControllerV1.java 하나만 살펴보자.
앞서 말했다시피 Front Controller Pattern을 적용한 후 컨트롤러는 Servlet으로 사용이 되지 않는다.
여기서 ControllerV1를 받아서 재정의 하고 있는것이 보이는데 이는 다향성을 지향하기 위함이다.

요청을 넘겨받은 컨트롤러는 처리해야하는 로직을 수행후 HttpServletRequest 객체에 데이터를 저장후 view에게 forward한다.

forward와 redirect는 약간의 차이가 있는데, forward는 서버 내부에서 요청을 보내는것 이고, redirect는 client에게 응답이 갔다가 다시 서버에 요청을 하는 방식이라고 한다.

정리
Spring에서의 DispatcherServlet이 Front Controller Pattern으로 구현이 되어 있고 그렇기에 사용자의 요청URL에 따라서 자동으로 알맞는 컨트롤러를 매핑해줄 수 있다.

profile
맨땅에 헤딩 장인

0개의 댓글