> For the complete documentation index, see [llms.txt](https://heunnajo.gitbook.io/mvc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://heunnajo.gitbook.io/mvc/4.-mvc/1-v5.md).

# ⭐️유연한 컨트롤러1 - v5(어댑터 도입, 인터페이스3 처리)

인터페이스 3 뿐만 아니라 4 그리고 확장해서 인터페이스 종류와 상관없이 들어오는 모든 요청 URL과 이에 따른 인터페이스를 처리하기 위해 어댑터라는 개념을 도입한다.

![구조 이해 정말 중요⭐️⭐️⭐️⭐️⭐️](/files/-MeITRgQVQaJzjMPEvYK)

1. 어댑터 인터페이스를 구현한다.\
   \- supports : 들어오는 요청 지원 가능한지 판단\
   \- ModelView handle : 처리 가능한 컨트롤러 호출하고 실행\
   (컨트롤러는 ModelView를 반환하는 컨트롤러)

```java
package hello.servlet.web.frontcontroller.v5;

import hello.servlet.web.frontcontroller.ModelView;

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

//shift F6 : Rename
public interface MyHandlerAdapter {
    //들어오는 컨트롤러를 지원할 수 있는지 판단
    boolean supports(Object handler);
    ModelView handle(HttpServletRequest req, HttpServletResponse res,Object handler) throws ServletException, IOException;
}

```

2\. 어댑터 구현체를 만든다. - **Controller32를 처리할 수 있는 어댑터**라고 하면 될 것 같다.\
&#x20; 1\) 첫번째로 들어온 객체가 ControllerV32인지 판단하는 supports를 구현한다.\
&#x20;     인터페이스 ControllerV32의 인스턴스라면 true를 반환한다.\
&#x20;    Front Controller에서 supports로 ControllerV32만 걸러서 handle메서드를 실행할 것이기 때문에 아handle메서드는 handler가 ControllerV32라고 확정하고 생각해도 된다.\
&#x20; 2\) handle 메서드는 컨트롤러를 호출해서 실행하고, ModelView를 반환한다(ControllerV32와 동일)

```java
package hello.servlet.web.frontcontroller.v5.adapter;

import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v32.ControllerV32;
import hello.servlet.web.frontcontroller.v5.MyHandlerAdapter;

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

public class ControllerV32HandlerAdapter implements MyHandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof ControllerV32);
    }
    @Override
    public ModelView handle(HttpServletRequest req, HttpServletResponse res, Object handler) throws ServletException, IOException {
        ControllerV32 controller = (ControllerV32) handler;
        Map<String, String> paramMap = createParamMap(req);
        ModelView mv = controller.process(paramMap);

        return mv;
    }
    private Map<String, String> createParamMap(HttpServletRequest req) {
        //컨트롤러의 process에 Map<String,String> paramMap을 넘겨줘야한다!!!!!!
        Map<String,String> paramMap = new HashMap<>();
        req.getParameterNames().asIterator()
                .forEachRemaining(paramName->paramMap.put(paramName, req.getParameter(paramName)));
        return paramMap;
    }

}

```

3\. Front Controller 새로 구성\
기존에는 private Map\<String,ControllerV4> controllerMap 으로 해서 특정 인터페이스만 받았지만, 이 부분의 value를 Object로 받음으로써 다양한 인터페이스들을 받을 수 있다!!!

* initHandlerMappingMap() : URI에 따른 컨트롤러를 맵핑한다!
* **initHandlerAdapters()** : **MyHandlerAdapter 리스트**인 handlerAdapters에 **MyHandlerAdapter 구현체**인 **ControllerV32HandlerAdapter()**&#xB97C; 넣는다!⭐️⭐️⭐️⭐️⭐️
* service()\
  getHandler(req) : 요청 URI에 따른 컨트롤러를 반환한다!\
  &#x20;예를 들어 req가 v5/v3/new-form이면 handlerMappingMap에따라 MemberFormControllerV32가 리턴된다!**(handler = MemberFormControllerV32)**\
  ❤️⭐️**getHandlerAdapter(handler)** :  MyHandlerAdapter 리스트인 handlerAdapters를 다 뒤진다. (참고로 handlerAdapters에는 ControllerV32HandlerAdapter()가 있다) MyHandlerAdapter 인터페이스 변수 adapter는 리스트를 돌면서 ControllerV32HandlerAdapter를 받는다.\
  \=>조건문 검사 : adapter.supports(handler) => handler가 ControllerV32인터페이스 인스턴스인지 검사해서 맞다면 true가 리턴된다. (그렇지 않으면 IllegalArgumentException으로 예외처리) true이면 이 ControllerV32HandlerAdapter()가 adapter로 리턴된다!\
  \
  이까지 정리가 되면 이제 끝났다!\
  다시 돌아와서 adapter의 handle메서드로 컨트롤러 호출, 실행하고 ModelView를 반환한다.\
  \
  뷰리졸버로 뷰 매칭하고, 랜더링한다.

```java
//import문 생략
@WebServlet(name="frontControllerServletV5", urlPatterns = "/front-controller/v5/*")
public class FrontControllerServletV5 extends HttpServlet {
    private final Map<String,Object> handlerMappingMap = new HashMap<>();
    private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();

    //생성자
    public FrontControllerServletV5(){
        initHandlerMappingMap();//맵핑 정보 넣는다!Object기 때문에 인터페이스 종료 상관없이 다 들어감.
        initHandlerAdapters();
    }
    private void initHandlerMappingMap() {
        handlerMappingMap.put("/front-controller/v5/v32/members/new-form",new MemberFormControllerV32());
        handlerMappingMap.put("/front-controller/v5/v32/members/save",new MemberSaveControllerV32());
        handlerMappingMap.put("/front-controller/v5/v32/members",new MemberListControllerV32());
    }
    private void initHandlerAdapters() {
        handlerAdapters.add(new ControllerV32HandlerAdapter());//MyHandlerAdapter 구현체
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        //URI 맵핑하고 그에 따른 객체 리턴하는 함수로 구현!
        //코드가 깔끔해진다! 아 handler를 찾는구나!
        Object handler = getHandler(req);//핸들러 찾아와.MemberFormControllerV32반환.
        if(handler == null){
            res.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        MyHandlerAdapter adapter = getHandlerAdapter(handler);//핸들러 어댑터 찾아와.
        ModelView mv = adapter.handle(req, res, handler);//실제 컨트롤러 호출해서 ModelView 반환.

        String viewName = mv.getViewName();
        MyView view = viewResolver(viewName);
        view.render(mv.getModel(),req,res);
    }

    private MyHandlerAdapter getHandlerAdapter(Object handler) {//핸들러로 V32가 들어오면
        //handler = MemberFormControllerV32
        for (MyHandlerAdapter adapter : handlerAdapters) {//리스트 다 뒤진다.
            if(adapter.supports(handler)){//V32가 있으면 support는 지원할 수 있으므로 true리턴
                return adapter;//MyHandlerAdapter adapter를 리턴한다!
            }
        }
        throw new IllegalArgumentException("Handler Adapter를 찾을 수 없습니다.handler"+handler);
    }

    private Object getHandler(HttpServletRequest req) {
        //URI가 들어오면 handlerMappingMap에서 찾는다!
        //다양한 URL이 들어올 수  있고, 이에 따라 다양한 인터페이스가 실행되야하기 때문에 Object로 받는다!
        String requestURI = req.getRequestURI();// 이것은 /front-controller/v2/members/new-form와 같다
        return handlerMappingMap.get(requestURI);
    }
    private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }

}

```
