본문 바로가기

SpringMVC

[인프런 강의 복습]스프링 MVC 1편 - model 추가

■ Model 추가

1) 서블릿의 종속성 제거
- 요청 파라미터 정보를 자바의 Map으로 대신 넘기도록 하면 지금 구조에서는 컨트롤러가 서블릿 기술을 몰라도 동작할 수 있다.
- 현재 구현된 컨틀로러가 서블릿 기술을 전혀 사용하지 않도록 변경
- HttpServletRequest가 제공하는 파라미터는 프론트 컨트롤러가 paramMap에 담아 호출
- 응답 결과로 뷰 이름과 뷰에 전달할 Model 데이터를 포함하는 Modelview 객체를 반환


2) 뷰 이름 중복 제거
- 컨트롤러에서 지정하는 뷰 이름에 중복이 있다. 
- 컨트롤러는 뷰의 논리 이름을 반환하고 실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 단순화

 

■ ModelView

- 지금까지는 컨트롤러에서 서블릿에 종속적인 HttpServletRequest를 사용
- Model도 request.setAttribute()를 통해 데이터를 저장하고 뷰에 전달
- 서블릿의 종속성을 제거하기 위해 Model를 직접 만들고, view 이름을 전달하는 객체를 생성
- 컨트롤러에서 뷰에 필요한 데이터를 key, value로 넣어준다.
import java.util.HashMap;
import java.util.Map;

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

■ MemberSaveControllerV3 - 회원저장

- ModelView를 생성할 때 save-result라는 view의 논리적인 이름을 지정
- 실제 물리적인 이름은 프론트 컨트롤러에서 처리
- process() 메서드에 파라미터로 전달된 paramMap에는 파라미터 정보가 담겨있다. 
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v3.ControllerV3;
import org.springframework.ui.Model;

import java.util.Map;

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

        //Model에 데이터를 보관한다.
        ModelView modelView = new ModelView("save-result");
        modelView.getModel().put("member", member);

        return modelView;
    }
}

 

■ FrontControllerServletV3

- createParamMap() : HttpServletRequest에서 파라미터 정보를 꺼내서 Map으로 변환 
- 생성된 해당 Map은 컨트롤러에 전달하면서 호출

- viewResolver() : 컨트롤러가 반환하는 논리 뷰 이름을 실제 물리 뷰 경로로 변경, 실제 물리 경로가 있는 MyView객체를 반환
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.MyView;
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;

@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
public class FrontControllerServletV3 extends HttpServlet {

    private Map<String, ControllerV3> controllerMap = new HashMap<>();

    //설정정보, servlet이 생성될 때 Map이 생성
    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);   //404 에러를 호출
            return;
        }

        //paramHMap
        Map<String, String> paramMap = createParamMap(request);
        ModelView mv = controller.process(paramMap);

        String viewName = mv.getViewName();
        MyView view = viewResolver(viewName);
        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) {
        Map<String, String> paramMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName ->
                        paramMap.put(paramName, request.getParameter(paramName)));
        return paramMap;
    }
}

 

■ MyView

- MyView의 render() 메서드는 모델 정보도 함께 받는다. 
- modelToRequestAttribute() 메서드는 전달받은 모델 정보를 HttpServletRequest에 담아 view에 전달하게 된다. 
- view에선 request.getAttribute() 를 통해 필요한 데이터를 화면에 렌더링한다.
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

public class MyView {

    private String viewPath;

    public MyView(String viewPath) {
        this.viewPath = viewPath;
    }

    public void render(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }

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