아무나개발하자

프론트 컨트롤러 패턴 소개2 본문

Spring

프론트 컨트롤러 패턴 소개2

개발천재나천재 2022. 7. 8. 08:36

View 분리 - v2

앞서서 소개한 프론트 컨트롤어 패턴 소개1은 모든 컨트롤러에서 뷰로 이동하는 부분에 중복이 발생한다. 또한 코드도 복잡하고 깔끔하지 않아서 밑에 코드를 수정해 보려고 한다.

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

밑에 소스코드에서 ControllerV2의 인터페이스를 상속받은 controller클래스는 위에 코드를 모두 반복하고 있다. 위에 코드는 viewPath를 String으로 지정하고 viewPath에 따른 RequestDispatcher를 호출하여 Jsp로 forward하는 코드이다. 

이 부분을 깔끔하게 분리하기 위해 별도로 뷰를 처리하는 객체(MyView)를 만들자.

앞으로 만들 V2의 구조

MyView

package hello.servlet.web.frontcontroller;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyView {
    private String viewPath;

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

    //view가 렌더링되게 동작하는 함수
    public void render(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request,response);
    }
}

viewPath를 지정하고 viewPath에 따라 JSP를 forward하는 함수가 구현되어있다. 이 함수를 view가 랜더링되게 한다고 해서 render함수라고 칭했다.

ControllerV2

package hello.servlet.web.frontcontroller.v2;

import hello.servlet.web.frontcontroller.MyView;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface ControllerV2 {

    MyView process(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException;


}

모든 컨트롤러들이 구현해야 하는 인터페이스이다. 비즈니스 로직이 실행되는 process함수를 만들었다. process함수는 MyView객체를 반환하게 구현되어있다. 나중에 MyView객체는 frontControllerServlet 클래스에서 잘 사용하여 JSP를 랜더링 할 것이다.

frontControllerServletV2

package hello.servlet.web.frontcontroller.v2;

import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v2.controller.MemberFormControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberListControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberSaveControllerV2;

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;

//frontController가 하는 역할이 uri 정보에 따라 controller를 매핑시켜주는 역할을 한다.
@WebServlet(name = "frontControllerServletV2", urlPatterns = "/front-controller/v2/*")
public class FrontControllerServletV2 extends HttpServlet {

    //key : url, value : Controller
    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 {
        System.out.println("FrontControllerServletV2.service");

        //클라이언트로 부터 입력된 uri 정보를 받아온다.
        String requestURI = request.getRequestURI();

        //controllerMap으로 클라이언트로 부터 입력된 uri 정보를 통해 controller를 매핑.
        ControllerV2 controller = controllerMap.get(requestURI);

        //controller가 매핑되지 못했을 경우를 대비해서 만들어줌
        if(controller == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        //이전과 다르게 process함수를 수행하고 나면 jsp uri 주소를 반환한다.
        MyView view = controller.process(request, response);
        view.render(request,response);
    }


}

frontControllerServletV2에서는 uri에 따른 controller를 매핑시켜주고, 해당 controller를 process함수를 통해 비즈니스 로직을 수행한다, prcess함수를 통해 반환된 MyView객체를 통해 JSP로 render한다.

 

MemberFormControllerV2

public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        return new MyView("/WEB-INF/views/new-form.jsp");
    }

 

 

ControllerV2 인터베이스를 구현한것이다.

 

MemberListControllerV2

private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ArrayList<Member> members = memberRepository.findAll();

        request.setAttribute("members", members);

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

ControllerV2 인터베이스를 구현한것이다.

MemberSaveControllerV2

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

        request.setAttribute("member", member);

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

ControllerV2 인터베이스를 구현한것이다.

 

컨트롤러 클래스를 보게되면 확실히 비즈니스 로직만 수행한다고 느껴진다. 경로는 지정해서 MyView객체로 보내 frontControllerServletV2에서 JSP로 render해주게 된다.

 

코드 : refactor : View분리-v2

https://github.com/dlqjagml/spring/commits/master

출처 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1

'Spring' 카테고리의 다른 글

HTTP 메시지 컨버터2  (0) 2022.07.16
HTTP 메시지 컨버터  (0) 2022.07.14
프론트 컨트롤러 패턴 소개4  (0) 2022.07.10
프론트 컨트롤러 패턴 소개3  (0) 2022.07.09
프론트 컨트롤러 패턴 소개1  (0) 2022.07.07