2 분 소요

인프런 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술편을 학습하고 정리한 내용 입니다.

자 이제

1
2
3
String viewPath = "/WEB-INF/views/save-result.jsp";  
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);  
dispatcher.forward(request, response);

각 컨트롤러 마다 반복 되던 이 행위를 분리 시켜서 깔끔하게 만들어 보자.

MyView 뷰 객체는 이후 다른 버전에서도 함께 사용하므로 패키지 위치를 frontcontroller에 두었다.

hello.servlet.web.frontcontroller.MyView

1
2
3
4
5
6
7
8
9
10
11
12
13
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);  
    }  
}

생성자를 통해 view의 위치를 받게 되고,

render() 이 메서드를 통해 기존 해오던 forward 행위를 공통으로 수행하게 된다.

이제 MVC 프레임워크 만들기 - V1 에서 했던 것 처럼 만들어 보자.

먼저 ControllerV2 인터페이스 이다.

hello.servlet.web.frontcontroller.v2.ControllerV2

1
2
3
public interface ControllerV2 {  
    MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;  
}

크게 달라진 건 없지만 MyView 객체를 리턴 하도록 만들었다.

이제 컨트롤러 3개 폼, 저장, 리스트를 만들러 가보자.

hello.servlet.web.frontcontroller.v2.controller.MemberFormControllerV2

1
2
3
4
5
6
public class MemberFormControllerV2 implements ControllerV2 {  
    @Override  
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        return new MyView("/WEB-INF/views/new-form.jsp");  
    }  
}

코드가 매우 간결해 졌다. MyView객체를 만들어서 view 위치를 넘겨버리면 끝이다.

hello.servlet.web.frontcontroller.v2.controller.MemberSaveControllerV2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MemberSaveControllerV2 implements ControllerV2 {  
    private MemberRepository memberRepository = MemberRepository.getInstance();  
    @Override  
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        String username = request.getParameter("username");  
        int age = Integer.parseInt(request.getParameter("age"));  
  
        Member member = new Member(username, age);  
        memberRepository.save(member);  
  
        // Model에 데이터를 보관한다.  
        request.setAttribute("member", member);  
  
        return new MyView("/WEB-INF/views/save-result.jsp");  
    }  
}

저장 로직이 있지만, 매우 간결해 졌다.

hello.servlet.web.frontcontroller.v2.controller.MemberListControllerV2

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MemberListControllerV2 implements ControllerV2 {  
  
    private MemberRepository memberRepository = MemberRepository.getInstance();  
    @Override  
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  
        List<Member> members = memberRepository.findAll();  
        request.setAttribute("members", members);  
  
        return new MyView("/WEB-INF/views/members.jsp");  
  
    }  
}

마지막으로 리스트 컨트롤러 이다.

이제 프론트 컨트롤러를 만들어 보자.

hello.servlet.web.frontcontroller.v2.FrontControllerServletV2

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
@WebServlet(name = "frontControllerServletV2", urlPatterns = "/front-controller/v2/*")  
public class FrontControllerServletV2 extends HttpServlet {  
  
    private Map<String, ControllerV2> controllerMap = new HashMap<>();  
  
    public FrontControllerServletV2() {  
        controllerMap.put("/front-controller/v2/members/new-form", new MemberFormControllerV2());  
        controllerMap.put("/front-controller/v2/members/save", new MemberSaveControllerV2());  
        controllerMap.put("/front-controller/v2/members", new MemberListControllerV2());  
    }  
  
    @Override  
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        String requestURI = request.getRequestURI();  
  
        ControllerV2 controller = controllerMap.get(requestURI);  
        if (controller == null) {  
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);  
            return;  
        }  
  
        MyView view = controller.process(request, response);  
        view.render(request, response);  
    }  
}

자 V1 때와 마찬가지로 Map 자료구조 안에 미리 다 담아 놓고,

String requestURI = request.getRequestURI(); 로 들어온 값 확인 하고

1
2
MyView view = controller.process(request, response);
view.render(request, response);

ControllerV2의 반환 타입이 MyView이므로 프론트 컨트롤러는 컨트롤러의 호출 결과로 MyView를 반환 받는다.

그리고 view.render()를 호출하면 forward로직을 수행해서 JSP가 실행된다.

프론트 컨트롤러의 도입으로 MyView객체의 render()를 호출하는 부분을 모두 일관되게 처리할 수 있게 되었다. 각각의 컨트롤러는 MyView객체를 생성만 해서 반환하면 된다.

이 구조를 만든 것이다.

댓글남기기