본문 바로가기

spring

Front Controller (2)

이번에 분리할 부분은 view이다. view를 처리하는 객체를 만들어보자

출처: 김영한 MVC 1편

public class MyView {
    String viewPath;

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

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

지금 위에 보이는 코드를 보면 RequestDispatcher가 있는걸로 보아 실제 화면으로 가는 기능인것 같은데 실제 가는 경로는 넣는 부분에 viewPath라는 변수가 들어온다. 이 말인 즉슨, 다른 곳에서 기본생성자로 viewPath를 받는 호출이 생기게 되서 받은 매개변수로 포워딩 하는 모습을 보게 될 것이다. 다음에 보게 작성할 코드는 각각의 기능 컨트롤러에서 사용할 기능을 묶은 interface를 만들겠다.

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

이 코드는 앞서 V1에서도 사용한 코드이다. 이제 각각의 순 기능이 잇는 컨트롤러들을 만들어보자. 앞서 V1에서 만든 코드와 거의 흡사하지만 차이점이 있다.

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

앞에서 사용한 방식과의 차이점은 V1에서는 각각의 컨트롤러에서 직접 디스패처로 포워딩을 했지만 포워딩을 하는 뷰로 이동하는 객체를 따로 만들었기 때문에 그 객체의 기본생성자를 호출해서 viewPath에 담아서 리턴을 한 모습이다. 이제 각각의 컨트롤러로 이동할 수 있는 FrontController만 만들면 끝난다.

@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 {
        System.out.println("frontControllerServletVdd2.service");

        String requestURI = request.getRequestURI();

        ControllerV2 controller = controllerMap.get(requestURI); // 해당 키 값의 value 추출
        if(controller == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        MyView myView = controller.process(request,response);
        myView.render(request,response);
    }
}

이번 FrontController 역시 앞서 만들었던 V1에서 V2로 수정을 하고 실제 service되는 부분을 보게 되면 우리는 매핑된 주소에 따라 각각의 컨트롤러의 생성자를 만들었고 이 컨트롤러의 순기능들을 실행하고 ( 입력 , 저장 , 목록보기 ) 각각의 컨트롤러에서 기능이 모두 수행되면 지정한 viewPath를 가지고 myView라는 포워딩이 실제로 실행되는 객체에 기본 생성자를 만들어 viewPath까지 만들게 되어 그 값으로 render라는 메서드가 실행되면서 포워딩이 되게 된다.

'spring' 카테고리의 다른 글

Front Controller (4)  (0) 2023.03.19
Front Controller (3)  (0) 2023.03.18
Front Controller (1)  (0) 2023.03.16
MVC 적용하기  (0) 2023.03.08
MVC 개요  (0) 2023.03.05