MVC 패턴 구현(2) : 모델 2 구조를 이용한 MVC 패턴(1)

de_sj_awa·2021년 5월 23일
2

모델 2 구조를 이용해서 MVC 패턴을 구현해보자. MVC 패턴의 구현 방법은 서블릿만 이용하는 단순한 방법부터 파일로부터 설정 정보를 읽어오는 복잡한 방법까지 다양한 형태로 존재한다. 여기서는 가장 손쉬운 구현 방법부터 커맨드 패턴을 기반으로 한 구현 방법까지 살펴볼 것이다.

1. 모델 2 구조의 구현 방법 : 기본 MVC 패턴 구현 기법

MVC 패턴을 구현하려면 기본이 되는 모델 2 구조를 구현하는 방법을 몸에 익혀야 한다. 왜냐면, 모델 2 구조를 위한 서블릿을 구현하는지, 서블릿과 JSP는 어떻게 정보를 주고받는지 등에 대한 기본 개념을 익힌 후에야 비로소 MVC 패턴을 체계적으로 구현하는 방법을 단계적으로 살펴볼 수 있기 때문이다.

여기서 살펴볼 모델 2 구조의 예제는 다음과 같이 간단한 기능을 제공하는 예제이다.

  1. 서블릿은 화면에 출력할 메시지를 생성해서 JSP에 전달한다.
  2. JSP는 서블릿으로부터 전달받아 메시지를 화면에 출력한다.

먼저, 서블릿 클래스에 대해서 살펴보자. 서블릿 클래스는 컨트롤러의 역할을 한다. 컨트롤러 서블릿은 위의 그림에서 보듯이 5가지 단계에 걸쳐서 동작한다. 이 5가지 단계를 구현한 전형적인 서블릿 클래스의 코드는 아래 예제 코드와 같다.

public class ControllerServlet extends HttpServlet {
    // 1단계, HTTP 요청 받음
    public void doGet(HttpServletRequest request, HttpServletResponse response) 
    	throws IOException, ServletException{
        	processRequest(request, response);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    	throws IOException, ServletException{
        	processRequest(request, response);
    }
    
    private void processRequest(HttpServlet request, HttpServletResponse response)
    	// 2단계, 요청 분석
    	// request 객체로부터 사용자의 요청을 분석하는 코드
    	...
    
    	// 3단계, 모델을 사용하여 요청한 기능을 수행한다.
    	// 사용자에 요청에 따라 알맞은 코드
    
    	// 4단계, request나 session에 처리 결과를 저장
    	request.setAttribute("result", resultObject);  // 이런 형태의 코드
        ...
        
        // 5단계. RequestDispatcher를 사용하여 알맞은 뷰로 포워딩
        RequestDispatcher dispatcher = request.getRequestDispatcher("/view.jsp");
        dispatcher.forward(request, response);
    }
}    

웹 브라우저가 GET 방식으로 보내든 POST 방식으로 보내든 컨트롤러는 1단계에서 일단 processRequest() 메서드로 웹 브라우저의 요청을 전달한다. processRequest() 메서드는 나머지 네 과정을 차례대로 실행한다. 먼저 2단계에서는, 웹 브라우저가 type 파라미터를 사용하여 사용자의 요청을 전송한다면 다음과 같은 코드를 사용해서 사용자의 요청을 분석할 것이다.

// 2단계. 요청 분석
String type = request.getParameter("type");

// 3단계. 요청한 내용에 따라 알맞은 모델 선택 및 실행
if(type.equals("a")){
    ...
}else if(type.equals("b")){
    ...
}

3단계에서는 사용자의 요청에 따라서 필요한 기능을 수행한 뒤 결과값을 생성한다.

4단계에서는 request 객체나 session 객체의 속성에 결과값을 저장한다. 이렇게 저장한 결과값은 뷰의 역할을 하는 JSP 페이지에서 사용한다. 보통은 다음과 같은 코드를 사용한다.

request.setAttribute("result", resultObject);

마지막 5단계에서는 RequestDispatcher.forward() 메서드를 사용해서 결과를 생성할 뷰로 이동한다.

앞에서 보여준 컨트롤러 서블릿 코드를 사용하는 예제를 작성해보자. 이 예제를 웹 브라우저가 전송한 type 파라미터의 값에 따라서 다른 결과값을 생성해서 뷰에 전달하는 컨트롤러 서블릿이다. 소스 코드는 아래 예제 코드와 같다.

package mvc.simple;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

public class SimpleController extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        processRequest(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        processRequest(request, response);
    }
    
    private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        // 2단계, 요청 파악
        // request 객체로부터 사용자의 요청을 파악하는 코드
        String type = request.getParameter("type");
        
        // 3단계, 요청한 기능을 수행한다.
        // 사용자의 요청에 따라 알맞은 코드
        Object resultObject = null;
        if(type == null || type.equals("greeting")){
            resultObject = "안녕하세요";
        }else if(type.equals("date")){
            resultObject = new java.util.Date();
        }else{
            resultObject = "Invalid Type";
        }
        
        // 4단계, request나 session에 처리 결과를 저장
        request.setAttribute("result", resultObject);
        
        // 5단계, RequestDispatcher를 사용하여 알맞은 뷰로 포워딩
        RequestDispatcher dispatcher = request.getRequestDispatcher("/simpleView.jsp");
        dispatcher.forward(request, response);
    }
}

별도의 모델 코드를 만들지 않았으므로, 3단계에서는 컨트롤러 서블릿에서 직접 웹 브라우저의 요청을 처리하고 있다. 4단계에서는 3단계에서 생성한 객체를 request 객체의 "result" 속성의 값으로 저장한다. 마지막으로 5단계에서는 뷰 역할을 하는 "/simpleView.jsp"를 포워딩한다.

뷰 역할을 하는 simpleView.jsp는 컨트롤러가 전달한 값을 단순히 화면에 출력하도록 구현할 것이다. simpleView.jsp는 아래와 같다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

결과 : ${result}

</body>
</html>

서블릿 클래스를 실행하려면 web.xml 파일에 다음과 같이 요청 URL과 서블릿 간의 매핑을 입력해 주어야 한다. 아래 코드는 SimpleController 및 URL 매핑을 설정한 web.xml 파일의 예를 보여주고 싶다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
    <servlet>
        <servlet-name>SimpleController</servlet-name>
        <servlet-class>mvc.simple.SimpleController</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>SimpleController</servlet-name>
        <url-pattern>/simple</url-pattern>
    </servlet-mapping>
</web-app>

실제로 웹 브라우저에 다음과 같이 type 파라미터의 값으로 date를 전달해야 한다.

http://localhost:8080/chap18/simple?type=date

SimpleController의 서블릿은 tye 파라미터의 값이 "date"이므로 Date 객체를 생성해서 request의 "result" 속성에 저장한 뒤 simpleView.jsp로 포워딩한다. 따라서, simpleView.jsp는 현재 시간을 담고 있는 객체의 내용을 출력할 것이다. 실제 웹 브라우저에 출력되는 내용은 다음과 같다.

위 예제를 보면 JSP로 쉽게 구현할 수 잇는 것을 애써 서블릿을 만들면서 모델 2 구조로 구현한 것 같다는 느낌을 받을 것이다. 물론, 간단한 웹 페이지는 JSP로 구현하는 것이 좋지만, 웹 어플리케이션의 규모가 커지고 복잡해질수록 MVC 패턴을 기반을 기반으로 웹 어플리케이션을 구현해야 유지보수의 확장이 편리해진다.
예를 들어, MVC 패턴을 사용하면 JSP 페이지는 로직을 처리하는 코드가 포함되어 있지 않기 때문에, UI를 변경해야 하는 경우 로직 코드는 손댈 필요 없이 UI 코드만 변경하면 된다. 즉, 게시판의 목록을 보여주는 형태가 변경된다 하더라도 로직 코드를 전혀 손댈 필요 없이 JSP 코드만 변경하면 되는 것이다. 또한, 로직 코드와 UI 코드가 섞여 있지 않기 때문에 JSP 코드를 변경하는 작업이 더욱 쉬워진다.

참고

  • 최범균의 JSP2.3 웹 프로그래밍
profile
이것저것 관심많은 개발자.

0개의 댓글