# Model 분리 - v3

1. 컨트롤러의 Servlet 종속성 제거 => View 이름까지 전달하는 Model 직접 생성
2. 뷰 이름 중복 제거 => 컨트롤러는 뷰의 논리 이름을 반환하고, "ViewResolver"로 논리 이름을 물리 이름으로 매칭시켜서 반환한다!

**ModelView**

**Model : Map(String,Object)**\
**View : 뷰의 논리적 이름**

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

import java.util.HashMap;
import java.util.Map;

public class ModelView {
    //view의 논리적 이름을 가져간다.
    private String viewName;
    private Map<String,Object> model = new HashMap<>();

    public ModelView(String viewName) {
        this.viewName = viewName;
    }

    public String getViewName() {
        return viewName;
    }

    public void setViewName(String viewName) {
        this.viewName = viewName;
    }

    public Map<String, Object> getModel() {
        return model;
    }

    public void setModel(Map<String, Object> model) {
        this.model = model;
    }
}

```

FrontController의 달라진 점을 집중적으로 보자.\
Model 객체를 직접 생성하였다. createParamMap은 request의 모든 데이터들을 맵으로 저장하고, 이 맵을 리턴한다! 이 맵 데이터들은 곧 **Model**이 된다!

각 컨트롤러는 ModelView 객체를 리턴한다!

controller.process()는 컨트롤러에 따라 다른 동작을 실행하는데 save이면 memberRepository에 member객체를 생성하여 전달받은 paramMap 정보 저장한다! 그리고 컨트롤러 내부에서 ModelView 객체를 생성해서 논리적 이름과 Model(맵)을 담아서 저장하고, 이 ModelView 객체를 반환한다!

리턴된 ModelView 객체의 논리적이름을 가져와 viewResolver함수로 논리 이름을 실제 물리이름으로 매칭시키고, ModelView의 Model(맵) 객체와 request,response를 함께 넘겨주어 렌더링 함수 호출한다!

MyView의 render(..,..,..) 생성자는 첫번째 파라미터인 Model을 받아서 이 Model(맵)을 다 꺼내서 JSP읽고 쓸 수 있도록 HttpServletRequest에 setAttribute한다!

```java
Map<String,String> paramMap = createParamMap(req);//Model.
ModelView mv = controller.process(paramMap);//컨트롤러에따라 다른 동작 실행.
String viewName = mv.getViewName();//View(논리이름).
MyView view = viewResolver(viewName);//논리이름->물리이름으로 매칭.
view.render(mv.getModel(),req,resp);//모델도함께 넘겨주면서 렌더링.
```

MyView 클래스 내부에서 render 메서드 구현

```java
public void render(Map<String, Object> model, HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
  modelToRequestAttribute(model,req);
  RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
  dispatcher.forward(req,res);
}
private void modelToRequestAttribute(Map<String,Object> model, HttpServletRequest req){
//  key,value로 루프를 돌리는 Java8 문법
//  model.forEach((key,value)->req.setAttribute(key,value));
    model.forEach((key,value)->req.setAttribute(key,value));
}
```

createParamMap 함수

```java
private Map<String, String> createParamMap(HttpServletRequest req) {
        Map<String,String> paramMap = new HashMap<>();
        req.getParameterNames().asIterator()
                .forEachRemaining(paramName->paramMap.put(paramName,req.getParameter(paramName)));
        return paramMap;
    }
```

FrontControllerV3

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

import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v2.ControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberFormControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberListControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberSaveControllerV2;
import hello.servlet.web.frontcontroller.v3.controller.MemberFormControllerV3;
import hello.servlet.web.frontcontroller.v3.controller.MemberListControllerV3;
import hello.servlet.web.frontcontroller.v3.controller.MemberSaveControllerV3;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
//front-controller/v3/members/new-form
@WebServlet(name="frontControllerServletV3",urlPatterns = "/front-controller/v3/*")
public class FrontControllerServletV3 extends HttpServlet {
    //ControllerV2와 동일
    private Map<String, ControllerV3> controllerMap = new HashMap<>();

    public FrontControllerServletV3() {
        controllerMap.put("/front-controller/v3/members/new-form",new MemberFormControllerV3());
        controllerMap.put("/front-controller/v3/members/save",new MemberSaveControllerV3());
        controllerMap.put("/front-controller/v3/members",new MemberListControllerV3());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.맵핑
        String requestURI = req.getRequestURI();
        ControllerV3 controller = controllerMap.get(requestURI);
        if(controller == null){
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        
        Map<String,String> paramMap = createParamMap(req);//Model.
        ModelView mv = controller.process(paramMap);//컨트롤러에따라 다른 동작 실행.
        String viewName = mv.getViewName();//View(논리이름).
        MyView view = viewResolver(viewName);//논리이름->물리이름으로 매칭.
        view.render(mv.getModel(),req,resp);//모델도함께 넘겨주면서 렌더링.
    }

    private MyView viewResolver(String viewName) {
        return new MyView("WEB-INF/views/" + viewName + ".jsp");
    }

    private Map<String, String> createParamMap(HttpServletRequest req) {
        Map<String,String> paramMap = new HashMap<>();
        req.getParameterNames().asIterator()
                .forEachRemaining(paramName->paramMap.put(paramName,req.getParameter(paramName)));
        return paramMap;
    }
}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://heunnajo.gitbook.io/mvc/4.-mvc/model-v3.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
