프론트 컨트롤러

shinyeongwoon·2022년 12월 26일
0

spring MVC

목록 보기
13/32

프론트 컨트롤러 패턴 소개

프론트 컨트롤러 도입 후

Front Controller 패턴 특징

  • 프론트 컨트롤러 서블릿 하나로 클라이언트 요청을 받음
  • 프론트 컨트롤러가 요청에 맞는 컴트롤러를 찾아서 호출
  • 입구를 하나로!
  • 공통 처리 가능
  • 프론트 컴트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 됨

Spring web MVC와 프론트 컨트롤러

스프링 웹 MVC의 핵심도 바로 FrontController
스프링 웹 MVC의 DispatcherServlet이 FrontController 패턴으로 구현 되어 있음

Font Controller 도입 - v

프론트 컨트롤러를 단계적으로 도입해보자
이번 목표는 기존 코드를 최대한 유지하면서, 프론트 컨트롤러를 도입하는 것이다.
먼저 구조를 맞추어두고 점진적으로 리펙토링 한다.

V1 구조

경로 ) hello.servlet1.web.frontcontroller.v1

package hello.servlet1.web.frontcontroller.v1;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface ControllerV1 {

    void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;

}

서블릿과 비슷한 모양의 컨트롤러 인터페이스 도입
각 컨트롤러들은 이 인터페이스를 구현하면 된다.
프론트 컨트롤러는 이 인터페이스를 호출해서 구현과 관계없이 로직의 일관성을 가져갈 수 있다.

이 인터페이스를 구현한 컴트롤러를 만들어 보자.

회원 등록 컨트롤러

경로 : hello.servlet.web.frontcontroller.v1.controller

package hello.servlet1.web.frontcontroller.v1.controller;

import hello.servlet1.web.frontcontroller.v1.ControllerV1;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class MemberFormControllerV1 implements ControllerV1 {

    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String viewPath = "/WEB-INF/views/new-form.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request,response);
    }
}

회원 저장 컨트롤러

경로 : hello.servlet.web.frontcontroller.v1.controller

package hello.servlet1.web.frontcontroller.v1.controller;

import hello.servlet1.domain.member.Member;
import hello.servlet1.domain.member.MemberRepository;
import hello.servlet1.web.frontcontroller.v1.ControllerV1;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MemberSaveControllerV1 implements ControllerV1 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

        request.setAttribute("member",member);

        String viewPath = "/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request,response);

    }
}

회원 목록 컨트롤러

경로 : hello.servlet.web.frontcontroller.v1.controller

package hello.servlet1.web.frontcontroller.v1.controller;

import hello.servlet1.domain.member.Member;
import hello.servlet1.domain.member.MemberRepository;
import hello.servlet1.web.frontcontroller.v1.ControllerV1;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

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

    }
}

내부 로직은 기존 서블릿과 거의 같다.
이제 프론트 컨트롤러를 만들어보자

프론터 컨트롤러

경로 : hello.servlet.web.frontcontroller.v1

package hello.servlet1.web.frontcontroller.v1;

import hello.servlet1.web.frontcontroller.v1.controller.MemberFormControllerV1;
import hello.servlet1.web.frontcontroller.v1.controller.MemberListControllerV1;
import hello.servlet1.web.frontcontroller.v1.controller.MemberSaveControllerV1;

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

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

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

    public FrontControllerServlet1V1() {
        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 {
        System.out.println("FrontControllerServlet1V1.service");
        String requestURI = request.getRequestURI();

        ControllerV1 controller = controllerMap.get(requestURI);

        if(controller == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        controller.process(request,response);

    }
}

프론트 컨트롤러 분석

urlPattern

urlPattern = "/front-controller/v1/*" : /front-controller/v1를 포함하는 하위 모든 요청이 서블릿에서 받아 들인다.
예) /front-controller/v1,/front-controller/v1/a, /front-controller/v1/a/b

controllerMap

key : Mapping URL
value: 호출될 컨트롤러

service()

먼저 requestURI를 조회해서 실제 호출할 컨트롤러를 controllerMap에서 찾는다.
만약 없다면 404(SC_NOT_FOUND)상태 코드를 반환한다.
컨트롤러를 찾고 controller.process(request,response);을 호출해서 해당 컨트롤러를 실행한다.

JSP

JSP는 이전 MVC에서 사용했던 것을 그대로 사용

0개의 댓글