현의 개발 블로그

[MVC 프레임워크 만들기] View 분리하기 본문

스프링부트 이론/MVC

[MVC 프레임워크 만들기] View 분리하기

hyun2371 2023. 6. 30. 18:22

모든 컨트롤러에서 뷰로 이동하는 로직이 중복된다.

String viewPath = "/WEB-INF/views/members.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);

이 부분을 공통화하기 위해 뷰를 처리하는 객체를 만들 것이다.

이전 버전에서 업그레이드 되었기 때문에 V2라고 명명했다.

 

V2 구조

클라이언트가 http 요청을 한다.

front controller는 매핑 정보에서 컨트롤러를 조회하여 호출한다.

 

컨트롤러가 MyView 객체를 반환하면, FrontController가 해당 객체의 render를 호출한다.

MyView가 JSP를 forward 해준다.

 

과거에는 controller가 JSP를 직접 포워드 했다면, 지금은 MyView가 JSP를 포워드한다.

 

 

MyView

컨트롤러의 공통 로직을 MyView 객체에서 수행한다.

Controller에게 viewPath를 받으면, MyView가 JSP로 포워드 한다.

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

 

*기존의 V1과 비교

public class MemberFormControllerV1 implements ControllerV1 {
    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String viewPath = "/WEB-INF/views/new-form.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

 

Controller

회원 목록 조회 (회원 등록, 회원 저장도 MyView를 호출하는 유사한 로직)

public class MemberListControllerV2 implements ControllerV2{
    @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");
    }
}

각 컨트롤러는 dispatcher.forward()를 직접 생성해서 호출하지 않아도 된다.

MyView 객체에 경로를 넣고 생성해서 반환하면 된다.

 

 

회원 등록

MemberFormControllerV2의 process 내부 코드이다.

return new MyView("/WEB-INF/views/new-form.jsp");

 

회원 저장

MemberSaveControllerV2의 process() 내부 코드이다.

String username = request.getParameter("username");
int age = Integer.parseInt(request.getParamter("age"));

Member member = new Member(username, age);
memberRepository.save(member);

request.setAttribute("member", member");

return MyView("/WEB-INF/views/save-result.jsp");

 

 

Front Controller

@WebServlet(name = "frontControllerServlet2", urlPatterns = "/front-controller/v2/*")
public class FrontControllerServletV2 extends HttpServlet{
	private Map<String, ControllerV2> controllerMap = new HashMap<>();
    ....
}

 

생성자는 V1과 동일한 로직이다.

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

 

 

front controller는 컨트롤러의 호출 결과로 MyView를 반환 받는다.

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

@Override
protected void service(HttpServletRequest request, HttpServletResponse response){
    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);
}

 

전체 프로세스 정리

1. v2/members/new-form을 호출하면 FrontControllerServletV2가 호출된다.

2. controller map을 통해 MemberControllerV2를 찾아와서 process()를 호출한다.

3. 호출 결과로 MyView 객체가 경로와 함께 반환된다.

4. MyView 객체의 render()를 호출하면 viewPath로 JSP가 forward 된다.

 

 

 


Reference

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com

 

Comments