Home 섹션4) MVC 프레임워크 - v3. Model 추가
Post
Cancel

섹션4) MVC 프레임워크 - v3. Model 추가

본 포스트는 스프링 MVC 1편(김영한, 인프런) 강의를 통해 학습한 내용을 작성자 임의 대로 요약 및 정리한 것입니다.


1. Model 추가 - v3

1.1. 기능

- 서블릿 종속성 제거

    컨트롤러 입장에서
HttpServletRequest, HttpServletResponse는 불필요!
    요청 패러미터 정보는 자바 Map으로 대신 넘기면
현 구조에선 컨트롤러가 서블릿 몰라도 동작 가능

    request 객체를 Model로 사용 부분
==> 별도의 Model 객체 만들어서 반환하기

  궁극적 목표
: 컨트롤러가 서블릿 기술 전혀 사용 않도록 변경하기!

- 뷰 이름 중복 제거

  궁극적 목표
: 컨트롤러는 뷰의 논리 이름 반환하고,
실제 물리 위치 이름은 프론트 컨트롤러에서 처리하도록
단순화하기!!!

1.2. V3의 구조

  1. 클라이언트의 HTTP 요청
  2. FrontController –> 매핑 정보
    : URL 매핑 정보에서 컨트롤러 조회
  3. FrontController –> Controller
    : 컨트롤러 호출
  4. Controller –> FrontController
    : ModelView 반환
  5. FrontController –> viewResolver
    : MyView 반환
  6. FrontController –> MyView
    : render(model) 호출
  7. MyView
    : HTML 응답.

1.3. ModelView

    지금까지는
서블릿에 종속적인 HttpServletRequest 사용했고,
Modelrequest.setAttribute() 통해
데이터 저장하고 뷰에 전달.
    Model 직접만들고,
View 이름 전달하는 객체 만들기

/servlet/web/frontcontroller에서

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
    }
}

1.4. ControllerV3

/servlet/web/frontcontroller/v3에서

1
2
3
4
public interface ControllerV3 {

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

    이 컨트롤러에선 서블릿 전혀 사용 안 함!
==> 그 대신,
  HttpServletRequest가 제공하는 패러미터는
  프론트 컨트롤러가 paramMap 인자로 담아 호출함.

1.4.1 MemberFormControllerV3 - 회원 등록 폼

/servlet/web/frontcontroller/v3/controller에서

1
2
3
4
5
6
7
8
public class MemberFormControllerV3 
        implements ControllerV3 {
    @Override
    public ModelView process
            (Map<String, String> paramMap) {
        return new ModelView("new-form");
    }
}

    ModelView 생성 시,
new-form이라는 view의 논리적 이름을 지정함.
(실제 물리적 이름 ==> 프론트 컨트롤러에서 처리)

1.4.2. MemberSaveControllerV3 - 회원 저장

/servlet/web/frontcontroller/v3/controller에서

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

1.4.3 MemberListControllerV3 - 회원 목록

/servlet/web/frontcontroller/v3/controller에서

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
    }
}

1.4.4 FrontControllerServletV3 - 프론트 컨트롤러

/servlet/web/frontcontroller/v3에서

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@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;
        }

        // 여기서 오류 발생(일종의 시그니처)
//        MyView view = controller.process(request, response);

        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 static MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" 
                        + viewName 
                        + ".jsp");
    }

    private static 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;
    }
}
  • viewResolver()
    : 컨트롤러가 반환한 논리 뷰 이름을
    실제 물리 뷰 경로로 변경하고,
    실제 물리 경로가 있는 MyView 객체 반환함.
    • 논리 뷰 이름: members
    • 물리 뷰 이름: /WEB-INF/views/members.jsp
  • view.render(mv.getModel(), request, response)
    • 뷰 객체 통하여 HTML 화면 렌더링.
    • 뷰 객체의 render()
      모델 정보도 함께 받음.
    • JSP는 request.getAttribute()
      데이터를 조회함.
      –> 모델의 데이터를 꺼내서
        request.setAttribute()에 담음.
    • JSP로 포워드 하여
      JSP를 렌더링 함.

1.5. MyView

/servlet/web/frontcontroller에서

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
32
33
34
35
36
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 {
        // model에 있는 데이터를 req. attribute로 바꿈
        modelToRequestAttribute(model, request);
        RequestDispatcher dispatcher 
                            = request
                                .getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }

    private static void modelToRequestAttribute
        (Map<String, Object> model, 
         HttpServletRequest request) {
        model.forEach((key, value) 
                        -> request
                            .setAttribute(key, value));
    }
}
Contents