MVC 패턴 편
MVC 패턴에 대한 개념은 기업이 입사 오디션에서 많이 물어보는 부분이기 때문에 주의해서
보는 것이 좋다.
이번 인터뷰는 좀 긴 편이다. ‘나는 다 읽기 귀찮고, 개념만 잡을테야’ 하는 분들은
‘Q. 모델은 DAO 클래스와 서비스 클래스들, DTO(beans) 클래스로 이루어졌다라… 구체적으
로 설명해달라. 나는 구체적설명요청쟁이. ‘
이 질문까지만 보면 된다.
Q. MVC 패턴, MVC 패턴. 말만 들어도 어렵다. MBC 채널 방송도 아니고 이게 대체 무엇이란 말인가.
일단 MVC 패턴을 잡기 위해 모델 1구조와 모델 2구조를 먼저 보겠다.
MVC 패턴에는 (1)모델 1구조와 (2)모델 2구조가 있다.
(1) 모델 1 구조
먼저, 모델 1구조에 대해서 알아보도록 하자
(2) 모델 2 구조
모델 2구조는 모델 1구조를 좀 더 발전시킨 형태이다.
모델 1구조는 요청 및 응답을 받고 이를 전송하는 뷰를 통합해서 사용한다. 이해 비해 모델 2구조는
이를 분리하여 사용한다. 효율적이고 정확한 관리를 하기 위해서이다.
모델 2구조의 처리 과정은 다음과 같다.
서블릿으로 요청을 받고* 이를 서비스 클래스로 보낸 뒤 처리한다. 이때 처리된 결과(빈객체)를
request에 담아 응답 뷰(View)인 JSP에 전송*한다. 그러면 JSP가 웹 상에서 처리 결과를 보여줄 것이
다.
*하나의 서블릿이 요청을 받을 때, 여러 요청들을 한꺼번에 받을 수 있다. 는 것을 명심하라.
*처리 결과들의 속성들을 request에 담아 응답 뷰에 보낼 때 주로, forword/ sendRedirect 를 사용한다.
이제 대충, MVC 패턴이 무엇인지 감이 잡히지 않는가.
MVC 패턴은 ‘서버가 웹 상에서 클라이언트로부터 요청을 받고, 이를 어떻게 처리하여 클라이언트에
게 돌려주는가’ 를 구조화 시킨 것이다. 모델 1구조는 과거에 주로 사용되던 구조이며, 모델 2 구조는
모델1 구조를 좀 더 정교화 시킨 것이다.
모델 2 구조는 모델 1구조와 비교했을 때, 응답 및 요청을 받고 전달하는 뷰가 서블릿과 뷰로 분리 되
어있다. 그렇기 때문에 관리에 용이하다.
Q. MVC 패턴(모델 2 구조)의 구성을 구체적으로 보여달라.
이 그림이 MVC 패턴의 큰 구성이다. 먼저 사용자(클라이언트)가 1.요청을 하면 2.컨트롤러가 모델*과
컨택하여 요청을 처리한다. 처리가 끝나면 요청 처리 결과를 보여줄(=응답할) 3.뷰를 선택하고, 이를
통해 4.응답을 하는 것이다
*모델은 DAO/서비스 클래스, 결과 데이터 저장용(VO/DTO/Beans) 클래스들로 구성되어 있다.
Q. 이 MVC 구조에서 서블릿이 컨트롤러 역할을 한다고 했다. 서블릿의 역할과 처리 과정에 대해서 구체적으로 말해줄 수 있는가.
서블릿은 1번에서 doGet/doPost로 요청을 받는다. 2번에서 클라이언트가 요구하는 기능이 파라미터
를 필요로 하는가 아니면 url을 필요로 하는가를 구분한다. 3번에서 Dao 및 서비스 클래스들로 구성되
어 있는 모델과 컨택하여 요청을 처리하고 4.번에서 request/session에 저장한다. 4번에 이 결과를
forward/sendRedirect로 보내준다.
이를 간단하게 표현해 보겠다
- 요청 받기
- 분석
- 기능 요청
- 결과 저장
- 지정 view에게 전송
Q. 모델은 DAO 클래스와 서비스 클래스들, DTO(beans) 클래스로 이루어졌다라… 구체적으로 설명해달라. 나는 구체적설명요청쟁이.
맞다. 인터뷰이가 말한대로, 모델은
(1)서비스 클래스
(2)dao 클래스
(3)VO/DTO/Beans 클래스들*로 이루어져있다.
이들의 역할과 처리 과정은 다음과 같다.
*VO/DTO/Beans 클래스들. 이들은 결과 데이터 저장용이다.
Q. MVC 패턴의 코드 구성은 다음과 같을 것 같다.
맞다.
그런데, 명심해야 할 것은 이 방법은 (1)요청 처리가 getParameter()를 필요로 할 경우이다.
2/3/4/5단계를 자세히 보도록 하자.
자, 이제는 (2) 요청 처리가 url을 필요로 하는 경우를 보도록 하자.
예를 들어, 전체 url이 localhost./guest/List.do이다. 그런데 나는 List.do만 가져오고 싶다. 그렇기 때문
에 request.getContextPath()*로 자른다.
*이때, request.getContextPath()의 의미는 url에서 localhost를 의미한다. 이를 실행하고 나면 url은 ‘guest/List.do’이다.
*reqeusg.getContextPath().length()만큼 자른다. 이때 reqeusg.getContextPath().length()에 해당하는
길이는 ‘/guest’이다.
Q. 코드를 구현해달라.
두 가지 경우를 구현해 보겠다.
(1) getParameter로 요청 처리하는 경우
[Controller.java]
package filter;
import java.io.IOException;
import java.util.Date;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/page")
public class Controller extends HttpServlet {
private static final long serialVersionUID = 1L;
public Controller() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request, HttpServletResponse response) {
//1. 상요자 요청 분석
String command = request.getParameter("type");
//2. 요청 처리 --> 결과 데이터 만들기
Object resultObj = null;
if (command == null || command.equals("greeting")) {
resultObj = "안녕하세요.";
}else if(command.equals("date")) {
resultObj = new Date();
}else {
resultObj = "Invalid Type";
}
//3. 결과 데이터를 request 객체에 속성으로 저장
request.setAttribute("result", resultObj);
//4. 지정된 뷰(jsp 파일)로 포워딩 : 응답 처리
RequestDispatcher dispatcher = request.getRequestDispatcher("/simpleView.jsp");
try {
// request를 보내는 작업.
dispatcher.forward(request, response);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
[simpleView.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head><title>뷰</title></head>
<body>
결과: <%= request.getAttribute("result") %>
</body>
</html>
결과)
(2) url로 요청 처리하는 경우
[ControllerURI.java] *
(1)getParameter에서 사용했던 Controller.java 페이지 코드들을 주석처리하고 실행해야 한다. 아니면 충돌 에러 남.
package filter;
import java.io.IOException;
import java.util.Date;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
/*@WebServlet("/page")*/
public class ControllerURI extends HttpServlet {
private static final long serialVersionUID = 1L;
public ControllerURI() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request, HttpServletResponse response) {
//1. 상요자 요청 분석
String command = request.getRequestURI();
if(command.indexOf(request.getContextPath()) == 0 ) {
command = command.substring(request.getContextPath().length());
}
//2. 요청 처리 --> 결과 데이터 만들기
Object resultObj = null;
if (command == null || command.equals("/greeting")) {
resultObj = "안녕하세요.";
}else if(command.equals("/date")) {
resultObj = new Date();
}else {
resultObj = "Invalid Type";
}
//3. 결과 데이터를 request 객체에 속성으로 저장
request.setAttribute("result", resultObj);
//4. 지정된 뷰(jsp 파일)로 포워딩 : 응답 처리
RequestDispatcher dispatcher = request.getRequestDispatcher("/simpleView.jsp");
try {
// request를 보내는 작업.
dispatcher.forward(request, response);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
[simpleView.jsp]
(1)에서 사용했던 simpleView.jsp의 코드와 같다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head><title>뷰</title></head>
<body>
결과: <%= request.getAttribute("result") %>
</body>
</html>
결과)
(2)URL로 처리하는 경우, 데이터 입력을 할 때 URL로 해야한다.
Q. 예, 잘 봤습니다(박수). 설명 잘 들었다. 듣다 보니 생각한 것인데, 코드 구성과 코드가 간결
할 때는 모델2보다는 모델1을 사용하는 것이 더욱 효율적이지 않는가?
그렇다. 모델2가 모델1보다 뉴버전이라고 하지만 경우에 따라서는 모델1을 사용하는 것이
더욱 효율적일 때가 있다. 모델1과 모델2의 각 장단점은 다음과 같다.
댓글 없음:
댓글 쓰기