스프링 MVC-MVC 패턴 적용
MVC 패턴
MVC 패턴에 대해서는 이전에 공부했었지만 그림을 통해 간단하게 다시 보고가자.
가장 많이 사용되는 MVC 패턴이다. Controller는 서비스에 접근하여 현재 필요한 로직을 호출한다. Model은 Controller가 로직을 통해 도출해낸 데이터를 저장한다. View는 Model에 접근하여 데이터들을 받아온 뒤, 화면을 렌더링하는데 필요한 데이터를 담아 응답한다.
이런 식으로 각 역할을 분리하면 변경의 라이프 사이클이 다른 여러 코드들을 효과적으로 유지보수 할 수 있다. 예를 들면 View를 수정하면서 비즈니스 로직까지 같이 수정해야 하는 일은 거의 없기 때문이다.
request는 내부에 key와 value로 이루어진 데이터 저장소를 가지고 있다. 그러므로 request를 Model로써 사용하고, jsp를 View로, 서블릿을 Controller로 사용하여 MVC 패턴을 구현해보자.
MVC 패턴의 적용
MVC 패턴을 적용하여 멤버의 등록, 저장, 조회 파트를 리팩토링 했지만, 코드가 너무 길어지므로 대표적으로 저장 파트만 코드를 보도록 하겠다.
package hello.servlet.web.servletMVC;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {
MemberRepository memberRepository=MemberRepository.getInstance();
@Override
protected void service(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);
String viewPath = "/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
}
서블릿을 통해 구현한 회원 저장의 Controller이다. request에서 파라미터를 받아 멤버를 만들고, 서비스 역할인 MemberRepository 객체에 저장한다. Model 역할인 request에 멤버 객체를 저장하고, 나머지 역할은 View에 넘겨준다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
성공
<ul>
<li>id=${member.id}</li>
<li>username=${member.username}</li>
<li>age=${member.age}</li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>
jsp를 통해 구현한 회원 저장의 View이다. html을 통해 화면을 렌더링하면서 Model에 담긴 멤버의 데이터를 받아 함께 화면에 출력해준다.
이로써 Model과 View, Controller가 확실하게 분리된 모습을 볼 수 있다. 이후 화면의 출력에 문제가 생기거나 하면 View 로직만 변경하면 된다.
MVC 패턴의 한계
MVC 패턴을 사용하여 역할의 분리에는 성공했지만, 더 나은 방법이 있을거 같은 느낌이 든다. 컨트롤러에서는 View로 이동하는 코드가 항상 중복으로 호출되어야 했고, viewPath에서도 같은 경로를 중복으로 입력하는 경우가 많았다. response처럼 전혀 사용되지 않은 코드도 들어갔다.
무엇보다도 공통 관심사항을 넣기가 어렵다는 문제가 있다. 이전에 공통 관심사항과 핵심 관심사항에 대해 배웠는데, 만약 로깅, 시간 측정 등의 공통 관심사항이 지금의 코드에 들어가야 한다면 각 컨트롤러에서 매번 해당 공통 관심사항의 메서드를 호출해줘야 할 것이다. 이 또한 중복이다.
이 문제를 해결하기 위해서는 컨트롤러의 호출 전 수문장 역할을 하는 코드가 필요하다. 이를 프론트 컨트롤러(Front Controller)라고 하는데, 스프링 MVC의 핵심도 이 프론트 컨트롤러에 있다.