프론트 컨트롤러 패턴 소개

slee2·2022년 1월 6일
1

FrontController 패턴 특징

  • 프론트 컨트롤러 서블릿 하나로 클라이언트의 요청을 받음
  • 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출
  • 입구를 하나로한다.
  • 공통 처리 가능

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

프론트 컨트롤러 도입 - v1

구조를 맞추어두고 점진적으로 바꿔보기로 한다.

ControllerV1 인터페이스

위 인터페이스를 다형성을 이용해 각각의 컨트롤러를 불러올 것이다.

인터페이스를 세 가지로 구현을 한다.

  • MemberFormContollerV1
  • MemberSaveControllerV1
  • MemberListControllerV1

MemberFormControllerV1

MemberSaveControllerV1

MemberListControllerV1

FrontControllerServletV1

이제 프론트 컨트롤러를 만드는데, Map을 이용해 각 컨트롤러의 URI와 컨트롤러를 담아둔다. 그리고 처음에 /front-controller/v1/* 의 모든 경로는 이 컨트롤러로 들어온다. 그후에 getRequestURI()를 이용하여 주소를 가져와 컨트롤러가 있는지 찾는다.

그 후에 컨트롤러가 있다면 그 컨트롤러의 process로 넘겨주는 로직이다.

이런식으로 잘 동작하는 것을 확인할 수 있다.

View 분리 - v2

이 불편했던 직접 입력받은 경로들을 별도로 처리하는 객체를 만들 것이다.

MyView

위의 dispatcher를 간단하게 만들기 위해 이 기능의 처리를 MyView가 처리를 할 것이다.

생성자로 경로를 넣은 다음, render메서드를 호출하면 dispatcher가 자동으로 되는 로직이다.

ControllerV2 인터페이스

잘 보면 반환이 MyView로 바뀐것을 확인할 수 있다.

MemberFormControllerV2

이전의 3줄과는 다르게 한줄로 확실히 줄어든 것을 확인할 수 있다.

MemberSaveControllerV2

MemberListControllerV2

FrontControllerServletV2

마지막에 render 메서드를 이용해 dispatcher 처리를 MyView가 해준다.

Model 추가 - v3

v3에서는 뭘 하냐
먼저 request, response를 매개변수로 항상 받는데
사용하는 이유가 결국에는 파라미터를 받기 위해서이기 때문에
이 받는 방법을 다르게 해서 서블릿 기술에 의존하지 않도록 만들 것이다.

또, 중복되는 뷰 이름을 제거할 것이다.

/WEB-INF/views/new-form.jsp -> new-form
/WEB-INF/views/save-result.jsp -> save-result
/WEB-INF/views/members.jsp -> members

이번에는 HttpServletRequest를 사용하지 않고, 뷰에 전달할 데이터들을 Model을 별도로 만들어 사용할 것이다.

사실상 스프링 MVC에 있는 ModelAndView를 만든다고 생각하면 된다.

ModelView

ModelView에서 viewName과 model 두개가 있는데

viewName논리이름을 받을 것이다.(new-form, save, members)
나중에 앞뒤에 URI를 붙이는 작업을 하기 위함이다.

model에는 파라미터 정보를 받을 것이다.(username, age)

ControllerV3 인터페이스

이번에는 반환값이 ModelView로 되어있고, 매개변수도 paramMap으로 되어있다.

즉, 처음에 FrontController에서 request에 있는 모든 정보를 paramMap에 넣은 다음, 이를 받아서 ModelView로 반환하는 로직이다.

MemberFormControllerV3

MemberSaveControllerV3

MemberListControllerV3

FrontControllerServletV3

먼저 getStringStringMap 메서드에서
paramMap에 request에 있는 모든 파라미터 정보를 넣어준다.

그리고 그 paramMap을 컨트롤러에 넣어서 ModelView를 반환받는다.

여기서 ViewName은 논리이름(new-form, save,....)이므로 앞 뒤에 URI를 붙여서 절대경로로 만들어준다.

이를 MyView에 넣어준다.

MyView에 model을 매개변수로 추가하여 넣어준 뒤, request에 세팅해준다.

단순하고 실용적인 컨트롤러 - v4

이전 v3 버전은 중복 코드 제거와 url을 단순하게 만들어줌으로써 괜찮게 만들어준 코드이다.
하지만, 실제로 개발자가 단순하고 편리하게 사용할 수 있는 즉, 실용적이게 만드는 것도 중요하다.

그걸 위한 v4!

v3와 같은 구조이지만 컨트롤러가 ModelView를 반환하지 않고 ViewName만 반환한다는 차이점이 있다.

ControllerV4

반환값이 ModelView가 아니라 String이다. 이 String에는 ViewName을 넣을 것이다.

MemberFormControllerV4

엄청 간단해졌다.

MemberSaveControllerV4

이전과 다르게 매개변수에 있는 model에 파라미터 값을 넣고 viewName을 반환하는 것이 끝이다.

MemberListControllerV4

마찬가지이다.

FrontControllerServletV4

이전과 똑같은 코드에서 범위 부분이 바뀌었는데, 먼저 model을 새로 만들고, 이를 process에 넣어준다. 반환값으로 viewName을 받고 이를 처리하는 것이 끝이다.

사실 전체적인 코드의 흐름은 바뀐것이 크게 없지만, 개발자의 입장에서는 이 작은 아이디어로 엄청 편해졌다는 점이 있다. 프레임워크가 점진적으로 발전하는 과정이 이렇다는 것을 알 수 있다.

프레임워크나 공통 기능이 수고스러워야 사용하는 개발자가 편리해진다.

유연한 컨트롤러1 - v5

위 컨트롤러들의 문제는 V4 버전의 컨트롤러는 V1 버전의 컨트롤러를 사용할 수 없다는 불편한 점이 있다. 이를 해결하는것이 V5

위 문제를 전기 콘센트로 비유하면 v3 - 110v, v4 - 220v
인 느낌이다. 이 둘을 연결하기 위해서는 어댑터가 필요하다.

이렇게 나온것이 어댑터 패턴이다.

핸들러 어댑터 - 중간에 어댑터 역할을 하는 어댑터가 추가되었는데 이름이 핸들러 어댑터이다. 여기서 어댑터 역할을 해주는 덕분에 다양한 종류의 컨트롤러를 호출할 수 있다.

MyHandlerAdapter 인터페이스

실제로 HandlerAdapter라는 것이 있기 때문에 My를 붙였다.

ControllerV3HandlerAdapter

supports
handler가 ControllerV3에 있는지 확인하여 있으면 참, 없으면 거짓을 반환한다.

handle
controller에 있는 프로세스를 진행시킨 후에 ModelView를 받고 이를 반환한다.

FrontControllerServletV5

여기서는 다 보여주기 보다는 코드가 진행하면서 어떻게 진행하는지 보는방식으로 하겠다.

먼저 이전과 다르게 handlerMappingMapMap으로 String, Object를 받는다. 이는 ControllerV3가 아닌 다른 컨트롤러가 들어올 수도 있기 때문에 가장 최상위인 Object로 만든 것이다.

그리고 생성자에서 각각 URI 정보와 컨트롤러를 넣은 다음, V3 컨트롤러 어뎁터를 넣어준다.

이제 이 로직을 하나씩 보도록 하겠다.

getHandler

getHandler는 request에서 URI를 받아온 뒤 이 URI가 handlerMappingMap에 있는지 찾는다.

있다면 해당 URI에 맞는 컨트롤러를 반환하고, 없다면 null을 반환하고 404(SC_NOT_FOUND)를 호출하게 된다.

getHandlerAdapter

getHandlerAdapter는 handlerAdapters를 뒤지면서 컨트롤러가 V3컨트롤러인지 참, 거짓으로 판별한다.

맞다면 해당 어뎁터를 반환하고 틀리면 예외를 던진다.

handle

handle에서는 해당 컨트롤러로 들어가 프로세스를 진행하고 ModelView를 받아온다.

나머지는 똑같이 진행된다. viewName으로 MyView를 만든 뒤에 랜더링을 완료한다.

유연한 컨트롤러2 - v5

이건 이전거에 ControllerV4도 추가하는 것이 목표이다.

FrontControllerServletV5

전과 달라진 점은 위 그림 부분으로

V4 URI 추가
V4HandlerAdapter() 추가

근데 ControllerV4HandlerAdapter()는 없으므로 만들어야 한다.

ControllerV4HandlerAdapter

ControllerV3HandlerAdapter

위는 V3 어뎁터의 handler메서드이다. 이 메서드와 V4 부분의 차이점을 살펴보자.

먼저 큰 차이가 있는데

V4는 프로세스의 매개변수가 paramMap, model이다. 이전과 다르게 model을 만들어줘야한다. 그래서 model을 새로 만들어준다.

그리고
V3 프로세스는 ModelView를 만들어서 반환해주는데
V4 프로세스는 ViewName을 반환해준다.

그렇기 대문에 ModelView를 새로 만들어 viewName을 세팅해주고, modele도 넣어준 뒤에 mv를 반환해준다.

쉽게 말해 위 두 차이가 110v, 220v 어뎁터의 역할을 수행하는 것이다.

 

위와 같이 편리하게 여러 컨트롤러를 어뎁터를 통해 하나의 FrontController에서 관리할 수 있다.

그리고 위의 기능을 스프링은 어노테이션을 통해 사용할 수 있고, 스프링 MVC에는 지금까지 나온 내용과 거의 비슷한 구조를 가지고 있다.

0개의 댓글

관련 채용 정보