녕의 학습 기록

[Spring MVC 1] MVC 프레임워크 만들기 (3) 본문

Dev/Spring

[Spring MVC 1] MVC 프레임워크 만들기 (3)

kjyyjk 2023. 1. 28. 20:23

 학습 내용 

더 실용적이고 유연한 컨트롤러 개선 (model을 파라미터로 / 어댑터 패턴 적용)


* model을 파라미터로

 

앞에서는 컨트롤러에서 ModelView 객체 생성하고 다시 반환해야했다.

 

어떻게 보면 귀찮은 작업..!

 

그래서 컨트롤러는 ModelView가 아닌 ViewName만을 반환하게끔 개선했다.

 

그렇다면 model은 어떻게 처리하지 ? 싶었지만

 

Map으로 구현한 model을 프론트 컨트롤러에서 컨트롤러를 호출할 때 파라미터로 넘겨주었다.

 

컨트롤러 interface. 컨트롤러에서는 String 인 ViewName만을 반환한다.

 

즉, 컨트롤러 입장에서는 파라미터로 넘어온 Map(model)에 데이터만 넣고, 반환은 뷰 이름만 반환하면 된다.

 

 

구현 컨트롤러. 파라미터로 넘어온 model 객체에 데이터를 넣어주고 뷰의 논리 이름만을 반환.
프론트 컨트롤러

위의 프론트 컨트롤러에서 model 객체 (Map)를 생성하여 컨트롤러에게 파라미터로 넘기는 것을 확인 !

 

그리고 논리 이름인 ViewName이 반환되면 기존처럼 뷰 리졸버를 통해 물리 이름으로 변경 후 MyView 객체를 반환받고

 

render 해주면 끝.

 

render 할 때는 아까 생성한 model을 같이 넘겨주면 된다. ( 컨트롤러에서 model 객체에 데이터를 담았으니 )

view.render(model, request, response);

 

 

이렇게 해서 컨트롤러에서는 모델을 직접 생성할 필요 없이 뷰 이름만 반환하게끔 코드를 작성했다.

---> 개발자 입장에서는 매우 편리하고 깔끔해졌다.

 

 

 

* 어댑터 패턴

 

앞에서 개발해온 MVC 패턴은 다 좋은데, 한가지 방식의 인터페이스만 사용가능하다는 한계..

ex) ControllerV3 와 ControllerV4 호환이 불가

 

만약 다른 방식으로도 개발하고 싶으면?

 

두개가 안맞아서 중간에 뭐하나 끼워서 두개를 맞추는 것. 어댑터이다.

like) 일본여행 시 돼지코 어댑터

 

MVC 패턴에도 어댑터를 적용하여 여러 방식의 컨트롤러 처리할 수 있게끔!

 

전체적인 건 다음과 같다.

 

어댑터 패턴

핸들러 어댑터가 바로 중간 어댑터 역할을 한다.

 

여기서 핸들러는 쉽게 생각하면 바로 컨트롤러이다.

 

근데 어댑터를 만듬으로써 컨트롤러 뿐만 아니라 다른 종류의 것도 처리할 수 있기 때문에(어댑터를 통해)

더 큰 범주에서 핸들러라고 변경한 것이다.

 

* 어댑터 패턴 도입

 

핸들러 어댑터 인터페이스

핸들러 어댑터는 프론트 컨트롤러와 핸들러 사이를 연결해주는 역할.

 

supports 메서드는 넘어온 handler 가 해당 어댑터와 호환하는 지 체크한다.

 

프론트 컨트롤러에서 handle 메서드를 호출하면 어댑터에서는 handler의 process를 호출, 모델뷰 반환!

 

즉, 징검다리 역할 또는 돼지코 역할

 

 

핸들러 어댑터 인터페이스를 구현한 V3용 핸드러 어댑터

 

public boolean supports(Object handler){
	return (handler instanceof ControllerV3);
}

V3용 핸들러 어댑터이므로 파라미터로 넘어온 핸들러가 ControllerV3의 인스턴스인지 확인하는 것을 확인.

 

public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        ControllerV3 controller = (ControllerV3) handler;

        Map<String, String> paramMap = createParamMap(request);

        ModelView modelView = controller.process(paramMap);

        return modelView;
    }

handle 에서는 넘어온 Object 타입 handler를 ControllerV3 타입으로 캐스팅 !

 

이렇게 해도 되는건가 싶겠지만 이미 supports 메서드를 통해 handler 가 ControllerV3의 인스턴스라는 것을

체크하고 그에 맞는 본 핸들러 어댑터로 넘어온 것이기 때문에 캐스팅해도 문제 될 것이 없다.

 

controller.process(paramMap)  으로 컨트롤러 실행하고 반환된 ModelView를 반환 !

 

 

 

핸들러 어댑터를 적용한 프론트 컨트롤러

이전 프론트 컨트롤러와 비교하자면 이름이 변경된 것도 있고,

 

핸들러 어댑터를 저장하는 Map인 handlerAdapters 를 새로 만들었다.

 

	private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if (adapter.support(handler)) {
                return adapter;
            }
        }
        throw new IllegalArgumentException("handler adapter를 찾을 수 없습니다. handler =" + handler);
    }

handlerAdapters 에 저장되어있는 어댑터 중 파라미터로 넘어온 handler 와 호환 되는 어댑터를 찾아 반환한다.

 

위에서 살펴본 adapter의 support 메서드를 통해 호환이 가능한지 확인 !

 

 

service{

ModelView mv = adapter.handle(request, response, handler);

}

호환이 가능한 adapter 를 호출 ! adapter는 파라미터로 넘어온 handler( 여기서는 컨트롤러 ) 를 호출 !

 

프론트 컨트롤러는 이 과정에서 무조건 ModelView를 반환받도록 설계.

 

V3버전 또는 V4 버전의 컨트롤러는 반환하는 타입이 다르니까 중간에 어댑터를 통해 ModelView로 반환하게끔 하는거다.

 

추가로 컨트롤러를 호출할 때 넘겨야할 파라미터도 다르기 때문에 .

 

즉, Adapter는 핸들러에 맞는 형식으로 핸들러를 호출하고,

반환된 것을 어떻게든 ModelView로 바꾸어 프론트 컨트롤러에 반환하는 역할이다.

 

v4용 핸들러 어댑터

 

String viewName = controller.process(paramMap,model);

ModelView mv = new ModelView(viewName);

...

reutrn mv;

여기서 알 수 있듯이 V4컨트롤러는 파라미터로 넘겨야하는 것도, 반환되는 것도 V3와 다르다.

 

V4는 String을 반환하지만 어댑터는 ModelView를 반환해야하므로 직접 생성 후 형식에 맞추어 반환.

 

그렇기 때문에 해당 어댑터를 통해 호환되게끔 중간 다리 역할을 하고 있는 것이다 !!

 

 

 

V5의 프론트 컨트롤러를 통해 V3, V4 다 호환하는 모습을 확인 가능.

 

 

 

다형성과 어댑터를 이용해 기본 구조를 유지하며 MVC 프레임 워크 기능을 확장해보았다.

 

여기가지 해서 만든 프레임워크는 스프링 MVC와 매우 유사한 구조를 지니고 있다.

 


 다음 학습 내용 

 

스프링 MVC의 구조

 

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com