관심쟁이 영호

[#6-1 Spring Boot 정주행] MVC 프레임워크를 직접 만들어보자 본문

Bank-End/Spring Boot

[#6-1 Spring Boot 정주행] MVC 프레임워크를 직접 만들어보자

관심쟁이 영호 2021. 9. 12. 16:21
반응형

이전에 포스팅한 글에서 서블릿 dispatcher를 통해서 JSP를 반환하는 것까지 성공했다!

 

하지만 문제가 있었다.

 

이번 포스팅에서는 해당 문제들을 짚어보고 하나씩 해결해보면서

 

MVC 프레임워크를 만들어보는 과정을 가질 것이다.

 

(참고로 Spring 또한 해당 역사를 밟아오면서 발달한 것이다!)

 

 

 

[#5 Spring Boot 정주행] HTTP로 HTML을 응답해보자!

이번 시간에는 서버를 만들어서 html을 리턴해보자! 먼저 서버를 만들자. 다음에 나오는 코드는 이전 시간에 했던 프로젝트에서 계속 유지한다. [#3 Spring Boot 정주행] HttpServletRequest, HttpServletResponse

bestkingit.tistory.com

 

 


목차

  • 문제점
  • FrontController
  • FrontController 만들기
  • 문제점 2

 


문제점

 

이전 포스팅의 글에서는 여러 가지의 문제점이 있었다. 문제점은 다음과 같다.

 

 

  1. 포워드의 중복이 생겼다.

 

사용자가 여러가지의 요청을 하는데, 해당 요청을 할 때마다 다음과 같은 코드가 삽입된다.

// view가 저장되어있는 path 
String Path = ""/WEB-INF/views/test.jsp";

RequestDispatcher dispatcher = req.getRequestDispatcher(Path);
dispatcher.forward(req, resp);

 

  2. 사용되지 않을 때가 있는 코드

 

"HttpServletRequest req / HttpServletResponse resp" 둘 중 1개가 쓰이지 않을 경우도 있다.

그렇게 된다면 쓸 때 없는 메모리 낭비가 생기게 된다.

 

 

  3. 공통처리가 힘들다

 

기능이 점차적으로 증가할 것인데, dispatcher를 하나하나 지정 해주고 기능 따라 메서드까지 호출해야 함에 문제가 생길 수 있다.

 


FrontController

 

프론트 컨트롤러가 무엇일까?

다음 그림을 통해서 비교해보자.

프론트 컨트롤러 도입 전

 

프론트 컨트롤러 도입 후

 

그림으로 보면 바로 알 수 있을 것이다.

프런트 컨트롤러는 사용자의 요청을 가장 먼저 받게 된다.

그리고 요청에 따라 다른 Controller를 호출해준다.

 

이렇게 나눈 이유가 무엇일까??

이쪽에서 언급한 문제점들을 개선하기 위함이다.

 

FrontController에서 사용자의 요청에 대한 "공통 처리"를 할 수 있기 때문이다.

 

FrontController를 도입 하기 전에는 모든 Controller 앞에 "공통적인 로직"이 존재하는 것을 알 수 있다. 공통적인 로직의 코드가 어렵고 길다면 매우 힘들 것이다.

 

이제 FrontController에 해당 공통 로직을 한 번만 입력된다.

좀 더 간편해졌다.

 

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

 


FrontController 만들기

 

생성 순서를 생각해보자.

 

  1. 특정 요청을 FrontController로 받기
  2. 요청을 받고, 공통 로직을 수행한다.
  3. 요청에 해당하는 Controller를 호출한다.
  4. 사용자에게 html, json 등을 리턴해준다.

 

특정 요청을 FrontController로 받기

 

FrontController.java 생성

//servlet/test로 시작하는 모든 URI요청은 여기로 받는다.
@WebServlet(name = "frontController", urlPatterns = "servlet/test/*")
public class FrontController extends HttpServlet {

    private Map<String, TestController> controllerList = new HashMap<>();

    public FrontController(){
        controllerList.put("servlet/test/", new
                UserController());
        controllerList.put("servlet/test/register", new
                UserController());
        controllerList.put("servlet/test/users", new
                UserController());
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse
            response)
            throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        TestController controller = controllerList.get(requestURI);
        if (controller == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        controller.logic(request, response);
    }
}
  • FrontController이다.
  • 사용자의 요청에 따라 다른 컨트롤러를 호출해줄 HashMap을 가진다.
  • 각 url에 따라 다른 Controller를 호출한다. (현재는 1개의 컨트롤러가 끝이다.)
  • "service" 메서드에서 들어온 uri에 따라 매핑된 controller를 찾고 해당 controller의 logic 메서드를 호출한다.

 

 

TestController.java 생성

public interface TestController {

    void logic(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;


};
  • 자바 인터페이스 다형성을 통해서 서로 다른 객체를 하나의 HashMap에 저장하고, 호출하기 위해서 필요한 Interface를 선언해준다.
  • 이 interface를 구현하는 Controller는 logic이라는 메서드를 통해 컨트롤러 기능을 한다.

 

UserController.java 생성

public class UserController implements TestController{

    @Override
    public void logic(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        String viewPath = "/WEB-INF/views/test.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
};

 

  • TestController를 구현하는 것이다.
  • Controller만의 고유한 기능을 logic에서 수행하여야 한다.

 

코드 해설

 

  1. 사용자가 URI를 통해서 요청한다.
  2. 가장 먼저 FrontController에 요청이 도착한다.
  3. FrontController의 service 메서드에서 요청 URI에 맞는 Controller를 찾아서 호출한다. 없으면 상태 코드를 SC_NOT_FOUND로 설정한다.
  4. Controller의 login 함수가 실행되고, 해당하는 view를 사용자에게 리턴해준다.

 

이제 공통적인 로직을 FrontController에서 수행할 수 있게 되었다.

service 함수에서 URI 매핑을 성공하면, 해당하는 매핑에 따라 다른 로직을 적용하거나

여러 개의 Controller에 공통적인 처리를 할 수 있을 것이다.


문제점 2

 

아직 문제가 있다.

 

컨트롤러에 다음과 같은 코드가 있다.

 

String viewPath = "/WEB-INF/views/test.jsp";

RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);

dispatcher.forward(request, response);

 

해당 코드를 계속해서 적용하는 방식으로 정하게 된다면

모든 컨트롤러에 해당 코드가 포함되어 있게 된다.

 

그래서 다음 포스팅에서는 viewPath와 서블릿을 넘기는 forward 메서드를 별도로 빼줄 것이다!

 

 

300x250
Comments