Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

Model 추가 : v3 본문

인프런/[인프런] 스프링 MVC 1

Model 추가 : v3

Seung__ 2021. 9. 11. 11:12

1. Servlet 종속성 제거


  • Controller입장에서 HttpServletRequest, HttpServletReponse가 필요할까..?
  • Controller는 파라미터 정보만 필요하다.
  • Request객체를 model 객체로 대체해보자.
  • 그러면 Controller는 Servlet 기술에 대한 의존성이 없다. ㄱㅇㄷ

 

2. 뷰 이름 중복 제거


컨트롤러는 뷰의 논리 이름을 반환하고, 

실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 단순화

이렇게 하면 나중에 폴더 위치가 이동해서 frontcontroller만 고치면됨 ㄱㅇㄷ~

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

 

 

 

3. v3 구조


 

 

 

4. ModelView


  • 이전에는 컨트롤러에서 서블릿에 종속적인 HttpServletRequest를 사용함.
  • 그리고 Model은 request.setAttribute() 를 통해 데이터를 저장하고 뷰에 전달했음
  • 서블릿의 종속성을 제거하기 위해 Model을 직접 만들고, 
  • 추가로 View 이름까지 전달하는 객체를 만들자.
  • 뷰의 이름과 뷰를 렌더링할 때 필요한 model 객체를 가지고 있다. 
  • model은 단순히 map으로 되어 있으므로 컨트롤러에서 뷰에 필요한 데이터를 key, value로 넣어주면 된다.
public class ModelView {

    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;
    }
}

 

 

 

5. ControllerV3 Interface


  • paramMap을 받음
  • ModelView객체를 반환
  • 이 컨트롤러는 서블릿 기술을 전혀 사용하지 않는다. 
  • 따라서 구현이 매우 단순해지고, 테스트 코드 작성시 테스트 하기 쉽다.
  • HttpServletRequest가 제공하는 파라미터는 프론트 컨트롤러가 paramMap에 담아서 호출해주면 된다.
  • 응답 결과로 뷰 이름과 뷰에 전달할 Model 데이터를 포함하는 ModelView 객체를 반환하면 된다.
public interface ControllerV3 {

   ModelView process(Map<String, String> paramMap);

}

 

 

 

6. FrontController


  • HttpServletRequest로 넘어온 request정보를 가지고 pramMap<String,String>을 만듦.
    • ex -> "username" : "kim"
  • 각 Controller에서 return한 ModelView객체의 viewName(논리이름) 꺼냄.
  • 논리 이름을 가지고 물리 이름으로 변경한 MyView 생성.
  • MyView의 render() 에 model, request, reponse객체 넘겨줌.
  • view에서 jsp로 이동함.
@WebServlet(name = "FrontControllerServletV3", urlPatterns = "/front-controller/v3/*")
public class FrontControllerServletV3 extends HttpServlet {

    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 request, HttpServletResponse response) throws ServletException, IOException {

        String requestURI = request.getRequestURI();

        ControllerV3 controller = controllerMap.get(requestURI);
        if(controller == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

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

        ModelView mv = controller.process(paramMap);

        //논리 이름을 물리 이름으로 바꾸기
        String viewName = mv.getViewName();

        MyView view = viewResolver(viewName);

        //모델은 render에 넘겨줘야함.
        view.render(mv.getModel(), request,response);


    }

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

    private Map<String, String> createParamMap(HttpServletRequest request) {
        //paramMap
        Map<String, String> paramMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
        return paramMap;
    }
}
  • 뷰 리졸버
    • MyView view = viewResolver(viewName)
    • 컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경한다. 
    • 그리고 실제 물리 경로가 있는 MyView 객체를 반환한다.
    • 논리 뷰 이름: members
    • 물리 뷰 경로: /WEB-INF/views/members.jsp
    • view.render(mv.getModel(), request, response)
    • 뷰 객체를 통해서 HTML 화면을 렌더링 한다. 뷰 객체의 render() 는 모델 정보도 함께 받는다.
    • JSP는 request.getAttribute() 로 데이터를 조회하기 때문에, 
    • 모델의 데이터를 꺼내서  request.setAttribute() 로 담아둔다.
    • JSP로 포워드 해서 JSP를 렌더링 한다.
  • render()에 model을 넘겨주면 request에 담아줘야함.
  • JSP는 request객체에 setAttribute를 해줘야 사용할 수 있음.
    public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        modelToRequestAttribute(model, request);
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request,response);
    }
    
        private void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
        model.forEach((key, value) -> request.setAttribute(key, value));
    }

 

7. MemberFormControllerv3 


  • ModelView 객체에 jsp 논리이름 넣어서 return
  • ModelView 를 생성할 때 new-form 이라는 view의 논리적인 이름을 지정한다. 
  • 실제 물리적인 이름은 프론트 컨트롤러에서 처리한다.
public class MemberFormControllerV3 implements ControllerV3 {

    @Override
    public ModelView process(Map<String, String> paramMap) {
        return new ModelView("new-form");
    }
}

 

 

 

 

8. MemberSaveControllerV3


  • 넘어온 paramMap을 사용하여 Member 객체 생성 및 save.
  • jsp 논리 이름을 사용하여 ModelView 객체 생성
  • ModelView객체의 model에 member 넣기.
  • ModelView 객체 return.
  • paramMap.get("username");
  • 파라미터 정보는 map에 담겨있다. map에서 필요한 요청 파라미터를 조회하면 된다.
  • mv.getModel().put("member", member);
  • 모델은 단순한 map이므로 모델에 뷰에서 필요한 member 객체를 담고 반환한다.
public class MemberSaveControllerV3 implements ControllerV3 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public ModelView process(Map<String, String> paramMap) {

        String username = paramMap.get("username");
        int age = Integer.parseInt(paramMap.get("age"));

        Member member = new Member(username, age);

        memberRepository.save(member);

        ModelView mv = new ModelView("save-result");
        mv.getModel().put("member", member);

        return mv;
    }
}

 

 

 

 

9. ModelListControllerV3


  • paramMap으로 넘어온 정보를 가지고 findAll실행.
  • jsp의 논리 이름을 가지고 ModelView객체 생성.
  • ModelView 객체의 model에  members 넣기.
  • ModelView 객체 return
public class MemberListControllerV3 implements ControllerV3 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public ModelView process(Map<String, String> paramMap) {
        List<Member> members = memberRepository.findAll();

        ModelView mv = new ModelView("members");

        mv.getModel().put("members", members);

        return mv;

    }
}

 

 

10. 실행


  • localhost:8080/front-controller/v3/members/new-form  접속
  • frontCtonroller에서 controllerMap을 통해 uri에 해당하는 Controller 확인.
    • -->MemverFormControllerV3 
  •  HttpServletRequest에 담긴 request정보를 가지고 paramMap을 생성.
  • controller.process()에 pramMap 넘겨줌.
  • controller는 model과 view의 논리이름이 담긴 ModelView객체 반환.
  • FrontController는 넘어온 논리이름을 가지고 물리이름이 담긴 MyView객체 생성.
  • FrontController는 MyView객체의 render실행을 위해
  • ModelView객체의 model, HttpServlerRequest 객체, HttpServletResponse객체를 넘김.
  • MyView객체는 넘어온 model정보를 request.setAttribute를 통해 request에 정보를 담음.
  • MyView객체는 가지고있는 jsp 물리이름, request, response 객체를 가지고 JSP로 이동 -> HTML응답.

 

 

 

 

11. GitHub : 210911 FrontController V3


 

GitHub - bsh6463/MVC1

Contribute to bsh6463/MVC1 development by creating an account on GitHub.

github.com

 

'인프런 > [인프런] 스프링 MVC 1' 카테고리의 다른 글

Controller V5 -1  (0) 2021.09.11
Controller V4  (0) 2021.09.11
Controller->view이동 분리 : V2  (0) 2021.09.11
FrontController 도입 : v1  (0) 2021.09.10
Front Controller 패턴  (0) 2021.09.10
Comments