Java & Spring/Spring MVC

Spring MVC/Controller/V1/V2/V3/V4/V5

solgitae 2022. 6. 8. 22:02
728x90

• V1

기존에는 클라이언트의 요청마다 그에 맞는 컨트롤러를 찾는 방식이었는데, 공통적인 처리 등은 하나의 컨트롤러에서 처리를 하자라는 취지로 Front-Controller가 도입이 되었고, Controller 인터페이스 생성 후 Controller를 구현하여 사용한다. Front-Controller는 이 인터페이스 구현한 클래스들을 호출해서 로직의 일관성을 가져갈 수 있다.

 

 

• V2

아래의 중복된 코드를 줄이고자 MyView라는 객체를 만듦. 이 MyView객체에서 render()라는 메소드를 통해 위의 중복되는 코드를 반환할 수 있게끔 하였다. 즉, ControllerV2의 process()는 MyView객체를 반환하게 되고 역할이 종료된다.

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

• V3

Controller의 로직을 실행할 때 항상 매개변수로 HttpServletRequest, HttpServletResponse를 써왔고, Model도 request.setAttribute()를 써서 데이터를 저장하고 뷰에 전달해왔다. 그런데 이걸 계속 쓸 필요가 있을까? 그냥 Front-Controller에서 처리를 하면 되지 않을까? 라는 아이디어에서 나온 결과는 요청 파라미터 정보는 Java의 Map(Collection)타입으로 넘기도록 하고, 따로 모델을 만들어 View를 전달하도록 하는 것이다. 이렇게 할 경우에는 컨트롤러가 서블릿의 기술을 몰라도 동작할 수 있기 때문에 종속성을 제거할 수 있다는 장점이 있다. 이렇게 될 경우 테스트 코드의 작성도 쉽고(독립적으로 분리 가능하기 때문에 테스트가 수월함), 구현 코드도 매우 단순해진다.

 

그리고 Controller가 MyView를 반환할 때 viewResolver()를 써서 "/WEB-INF/view/.../"같은 중복을 물리 주소와 논리 주소로 나눈 후 "members"..처럼 논리 주소만 사용해서 요청 가능하게끔 한다.

 

• V4

종속성을 제거하고 여러 중복을 제거하는 등 그렇게 V3는 꽤 괜찮은 컨트롤러가 되었다. 다만 조금 아쉬운 점은 ModelView를 계속해서 생성하고 반환한다는 점이다. 개발자들이 더 편하게 구현을 할 수 있게끔 만들어진 게 V4이다.

 

FrontControllerServletV4는 인터페이스에 ModelView가 없다. 그렇기 때문에 반환을 ModelView가 아닌 뷰의 이름만 반환해주면 된다. model 객체는 파라미터로 전달되기 때문에 그냥 사용하자. FrontControllerServletV4는 이전 버전과 거의 동일하다. 이번 버전의 컨트롤러는 매우 단순하고 실용적이다. 기존 구조에서 모델을 파라미터로 넘기고, 뷰의 논리 이름을 반환한다는 작은 아이디어를 적용했을 뿐인데, 컨트롤러를 구현하는 개발자 입장에서 보면 이제 군더더기 없는 코드를 작성할 수 있다.

 

• V5

중간의 어댑터 역할을 하는 것이 추가가 되었는데 이름이 핸들러 어댑터이다. 이 핸들러 어댑터 덕분에 여러 종류의 컨트롤러를 호출할 수 있다. 핸들러는 컨트롤러의 이름을 넓은 범위로 확대 변경했다고 생각하면 될 것이다. 이렇게 변경된 이유는 어댑터가 있기 때문에 꼭 컨트롤러의 개념 뿐만 아니라 어떠한 것이든 해당하는 종류의 어댑터만 있으면 URL에 매핑해서 사용할 수 있다.

 

  1. 핸들러 매핑 정보를 조회했는데 만약 ControllerV4라면  ControllerV4를 처리할 수 있는 어댑터를 가지고 옴
  2. 기존에는 Front-Controller에서 바로 핸들러를 호출했는데 이제는 어댑터를 통해서 호출해야 함
  3. 그래서 이 어댑터한테 컨트롤러를 넘겨줘야 함 그러면 어댑터가 핸들러 대신 호출해주고 결과를 받은 다음에어댑터가 modelview를 프론트 컨트롤러에 반환해줌

 

*remind

• 핸들러: getHandler(request)를 이용해서 URI에 맞는 객체를 매핑해서 반환 (컨트롤러라고 생각하면 될 듯)

• 어댑터: getHandlerAdapter(handler)를 이용해서 adapter.support()을 해서 뒤져본 후에 지원되는 게 있으면 어댑터를 찾아서 반환한다. 그 후에 adapter.handle(request, response, handler)를 해서 이름처럼 어댑터로 컨트롤러를 호출해서 다룬다. 

• MyView: viewResolver(viewName)을 담아서 render() ! -> 클라이언트에게 렌더링해서 보여주는 용도

• ModelView: viewName을 가지고 있는 객체 !

• 뷰 리졸버: viewName(논리주소)만을 가지고 물리 주소로 만들어주는 역할을 함

 

 

*요약

• V1

프론트 컨트롤러를 도입

기존 구조를 최대한 유지하면서 프론트 컨트롤러를 도입

• V2

View 분류

단순 반복 되는 뷰 로직 분리

• V3

Model 추가

서블릿 종속성 제거

뷰 이름 중복 제거

• V4

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

v3와 거의 비슷

구현 입장에서 ModelView를 직접 생성해서 반환하지 않도록 편리한 인터페이스 제공

• V5

유연한 컨트롤러

어댑터 도입

어댑터를 추가해서 프레임워크를 유연하고 확장성 있게 설계