MVC 패턴이란?
MVC는 Model, View, Controller의 약자로 하나의 하나의 애플리케이션, 프로젝트를 구성할 때 그 구성을 세 가지의 역할로 구분한 패턴이다.
❓왜 MVC 패턴을 사용해야 할까?
그 질문에 답하기 위해서 자바 웹 페이지가 어떻게 변화하였는지 알아볼 필요가 있다.
자바 + servlet 코드 예시
@WebServlet(name = "memberSaveServlet", urlPatterns = "/servlet/members/save")
public class MemberSaveServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("MemberSaveServlet.service");
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
System.out.println("member = " + member);
memberRepository.save(member);
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter w = response.getWriter();
w.write("<html>\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
"</head>\n" +
"<body>\n" +
"성공\n" +
"<ul>\n" +
" <li>id="+member.getId()+"</li>\n" +
" <li>username="+member.getUsername()+"</li>\n" +
" <li>age="+member.getAge()+"</li>\n" +
"</ul>\n" +
"<a href=\"/index.html\">메인</a>\n" +
"</body>\n" +
"</html>");
}
}
자바 코드와 servlet으로 HTML과 자바 data값을 조합하여 페이지를 만들 수 있다.
❌단점
자바 코드로 만든 HTML 문서가 비효율적이다.
자바 코드에 하나하나 하드 코딩하는 것이 상당히 번거롭다
❓ 자바 코드에 text로 html을 생성하기보단 기존 HTML에 동적으로 변하는 부분만 자바 코드를 넣을 수 없을까?
jsp(java server pages)코드 예시
<%@ page import="mvc1practice1.mvc1practice1.domain.member.MemberRepository" %>
<%@ page import="mvc1practice1.mvc1practice1.domain.member.Member" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
MemberRepository memberRepository = MemberRepository.getInstance();
System.out.println("save.jsp");
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
System.out.println("member = " + member);
memberRepository.save(member);
%>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<ul>
<li>id = <%=member.getId()%></li>
<li>username=<%=member.getUsername()%></li>
<li>age=<%=member.getAge()%></li>
</ul>
<a href="index.html">메인</a>
</body>
</html>
HTML 페이지에 <% ~ %>를 활용하여 자바 코드를 출력해 동적으로 페이지를 생성한다.
💡JSP를 활용하여 View를 생성하는 HTML을 따로 분리할 수 있고 중간에 동적으로 변경이 필요한 부분만 자바 코드를 적용할 수 있다.
❌단점
HTML 페이지에 필요한 부분만 자바 코드를 넣어 자바 + servlet의 단점을 해결했지만 여전히 비즈니스 로직 + View가 함께 섞여있음
❓ 비즈니스 로직(자바 코드)은 서블릿에서, View(HTML 페이지)는 JSP에서 처리하여 비즈니스 로직과 View 역할을 분리할 순 없을까?
위에서 말했듯이 비즈니스 로직과 View를 모두 담당해 많은 역할을 담당
UI와 비즈니스 로직은 서로 종속적이지 않고 독립적이므로 변경의 라이프 사이클이 다른데 하나의 코드로 유지 보수하기 비효율적
💡 서블릿, JSP로 한번에 처리하던 것을 Controller, View로 분리하는 MVC 패턴 등장
Controller
: HTTP 요청 받아 파라미터 검증, 비즈니스 로직 실행, View에 전달할 결과 데이터를 모델에 담음Model
: View에서 출력할 데이터 담음(View는 출력만 하는 역할로 비즈니스 로직 몰라도 됨)View
: 모델에 담긴 데이터 출력.
- 클라이언트가 Controller를 호출한다.
- Controller가 Service, Repository(Database)에 접근하여 필요한 데이터를 가져온다.
- 가져온 데이터를 Model에 저장한다.
- 필요한 데이터를 Model에 담았으면 View Model을 전달한다.
- View에서 필요한 데이터들을 Model에서 꺼내 사용한다.
서블릿(Controller) 와 JSP(View)를 사용한 MVC 코드
1. Controller(서블릿)
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {
private 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);
System.out.println("member = " + member);
memberRepository.save(member);
request.setAttribute("member", member);
String viewPath = "/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
}
2. View(JSP)
<%@ 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>
💡MVC 패턴을 활용하여 자바 코드와 View를 분리하여 각자 역할을 분리하여 구현할 수 있다.
MVC 패턴을 활용하여 역할을 잘 분리하였지만 한계가 존재하는데 다음과 같다.
1. controller에서 코드 중복
//forward 중복
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
//ViewPath 중복
String viewPath = "/WEB-INF/views/new-form.jsp";
2. 사용하지 않는 코드
HttpServletRequest request, HttpServletResponse response
response는 사용하지 않는 경우도 있지만 HttpServlet을 상속 받기 때문에 request, response를 항상 구현해야 한다.
3. 공통 처리 어려움
controller에 공통 기능이 많아질 경우 공통 메서드를 추출하면 될 것 같지만 HttpServlet을 상속 받고 service를 @Override 해서 사용하므로 메서드를 또 구현해야 함.
💡 컨트롤러 호출 전에 먼저 공통 기능을 처리하는 수문장 역할이 필요하다 -> 프론트 컨트롤러