[01. mvc 프레임워크 만들기 - 프론트 컨트롤러 패턴이란?][02. mvc 프레임워크 만들기 - 프론트 컨트롤러 도입]
[03. mvc 프레임워크 만들기 - View 분리][04. mvc 프레임워크 만들기 - Model 추가]
[05. mvc 프레임워크 만들기 - 단순하고 실용적인 컨트롤러][06. mvc 프레임워크 만들기 - 유연한 컨트롤러1]
[07. mvc 프레임워크 만들기 - 유연한 컨트롤러2][08. mvc 프레임워크 만들기 - 정리]

이전 시간까지 만들었던 Controller는 모두 공통로직이 들어가 있었다.

프론트 컨트롤러 도입시 하나의 공통 로직을 두고 각 Controller에서 필요한 로직은 각각의 Controller에 구현하게 된다.
FrontController의 특징
프론트 컨트롤러를 단계적으로 도입해보자.
이번 목표는 기존 코드를 최대한 유지하면서 프론트 컨트롤러를 도입하는 것이다.
먼저 구조를 맞추어두고 점진적으로 리펙터링 해보자!

ControllerV1
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface ControllerV1 {
void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}
공통로직을 작성해줄 ControllerV1은 interface로 만들어준다.
MemberControllerV1
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);
}
}
MemberSaveControllerV1
public class MemberListControllerV1 implements ControllerV1{
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
public class MemberSaveControllerV1 implements ControllerV1{
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);
// Model에 데이터를 보관한다.
request.setAttribute("member", member);
String viewPath = "/WEB-INF/views/save-result.jsp"; //해당 viewPath가 dispatcher에 의해 내부로 호출
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response); //내부에서 호출해줌
}
}
ControllerV1을 implements 하고 있는 3개의 Controller
비지니스로직은 mvc패턴으로 만들었던 코드를 그대로 사용한다.
frontControllerServletV1
@WebServlet(name = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*")
public class FrontControllerServletV1 extends HttpServlet{
private Map<String, ControllerV1> controllerMap = new HashMap<>();
private FrontControllerServletV1() { //기본 생성자
controllerMap.put("/front-controller/v1/members/new-form", new MemberFormControllerV1()); // 해당 url로 요청이 오면 매핑된 Controller가 생성됨
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("FrontControllerServletV1.service");
String requestUri = request.getRequestURI();
ControllerV1 controller = controllerMap.get(requestUri);
if(controller == null) { // 해당하는 requestUri가 존재하지 않을 경우
response.setStatus(HttpServletResponse.SC_NOT_FOUND); //404
return;
}
controller.process(request, response);
}
}
servlet을 통해 3개의 Controller에 요청을 보내줄 Controller다.
코드를 보면 Map 안에 요청 uri와 Controller 객체를 넣어준다. 클라이언트에서 요청이 들어오면
frontControllerServletV1.ervice() → 요청 uri가 일치한다면 → 각 Controller의 process 순으로
메서드가 작동한다. 여기서 다형성이라는 개념을 이해할 필요가 있다. service 메서드를 보면
부모객체인 ControllerV1 타입인 controller 객체가 uri를 담고 있다. 각 Controller는 부모객체인 ControllerV1을 상속받고 있기 때문에 부모객체에 담아 사용할 수 있다.
이렇게 작성하고 회원가입을 하면 회원List에 데이터가 잘들어오는 모습을 볼 수 있다.

frontController를 도입하고 보니 생각보다 간결하게 구현되지는 않는 것 같다.
여기서 어떤점들을 개선할 수 있는지 확인해서 좀더 보완하고 수정할 필요가 있는 것 같다.