Spring

[jsp] 모델2 기반의 MVC 패턴

sian han 2022. 5. 18. 21:16

※ 모델2 기반의 MVC 패턴

  = > MVC 패턴 = 모델2

 

 

MVC 패턴(Model-View-Controller pattern) 

  - 면접질문

  - 전통적인 GUI 기반의 어플리케이션을 구현하기 위한 디자인 패턴

 

 

 

▶ 모델1

 - JSP 혼자 북치고장구치고 다 하는게 모델1

 - 요청받고 응답하고 브라우저에 뿌려주는것 전부 JSP 가 함

 - 뷰와 컨트롤러가 같은 jsp 페이지 안에서 실행되어지고, jsp 로 요청하고 보여준다

     => 로직처리와 결과처리를 전부 JSP 가 하는데, 이렇게 섞이는 것보다 모든지 분리해서 작업하는게 좋다

 

 

 

▶ 모델2

  - 컨트롤러가 요청을 받아서 모델에 의뢰해서결과를 받아오고, 그 결과를 뷰한테줘서 보여준다

  - 컨트롤러는 가운데에서 중재하는 역할

  - 서블릿이 사용자의 요청을 받아서 비즈니스 로직을 처리하는 모델을 통해 수행 결과를 받아와

    해당 jsp 페이지에 결과를 보 내어 뷰가 사용자에 응답을 보내는 구조

  - 컨트롤러가 모델한테 결과를 받아서 request에 저장한 후 forward 로 보낸다

      => 왜 ? request 는 요청과 응답이 공유되니까 ! 

 

 

▷ 모델 model

  - 모델링하고 비즈니스 로직을 처리함
  - 비즈니스 로직 처리 클래스

  - ex ) 자바빈

 

▷ 컨트롤러 Controller

  - 어플리케이션의 흐름을 제어하는 것

  -컨트롤러는 사용자의 요청을 받아서 모델에 넘겨주고, 모델이 처리한 작업의 결과를 뷰에 보내주는 역할을 함

  - ex ) 서블릿

 

뷰view

  - 화면에 결과를 뿌림.응답하는 역할

  - ex ) jsp페이지

 

 

모델1과 모델2 의 비교 : 

 기존 처리과정 3단계

  1. 파라미터읽어오기

  2. DB 작업

  3. 화면에 보여주기

 

모델 1 ) 모두 jsp 에서 처리

모델 2 ) 1,2번은 컨트롤러가 진행하고 결과를 저장함. jsp 는 3번만 진행 

 

 

 

☞ POJO

  - 평이한 일반 자바클래스

     ㄴ 누구도 extend 하지않고 implement 하지않음.

  - 대부분의 모델은 POJO 로 코딩한다.

  - POJO 가 아닌 애들은 내가 필요하지않은 메서드를 사용해야 하는 등 문제가 있어 코딩하기 까다롭다

  - 스프링은 POJO 이다

  - ex ) DAO, VO, Service

 

 


 

※ MVC 기반 모델2 코딩

  - URI 자체를 명령어로 사용하는 방법

 

[1] web.xml 에서 매핑 

  - 매핑에서 하는 일 : 이런 명령어가 들어오면 이런 컨트롤러가 처리해 ! 

       = 요청사항이들어오면 코드를 변경할필요없이 매핑화일만 고쳐나가면 됨.

  - 매핑파일에서 uri에서 명령어를 추출하고 명령어에 해당하는 컨트롤러를 찾아서 메서드를 호출해서 일을 시킴

<servlet>
		<servlet-name>DispatcherServlet</servlet-name> //3
		<servlet-class>com.controller.DispatcherServlet</servlet-class> //4
		<init-param>
			<param-name>configFile</param-name>
			<param-value>/config/CommandPro.properties</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>DispatcherServlet</servlet-name> // 2
		<url-pattern>*.do</url-pattern> // 1
	</servlet-mapping>

  1. 어떤요청이든 (get or post) do 요청이 들어오면

  2. name 이 DispatcherServlet 인 서블렛으로 처리해라

  3. 서블릿 name 이 DispatcherServlet 인 애는 클래스 com.controller.DispatcherServlet 로 처리한다

 

 

 

[2] 요청하는 페이지 : travelForm2

<body>
	<h3>지역을 선택하시면 좋은 여행지를 추천해드립니다</h3>
	<form name="frm1" method="post"
		action="<%=request.getContextPath()%>/travel.do">
		<select name="city">
			<option value="강화">강화</option>
			<option value="강릉">강릉</option>
			<option value="해남">해남</option>
			<option value="거제">거제</option>
		</select> <br>
		<br> <input type="submit" value="확인">
	</form>
</body>
</html>

submit 을 하면 action = 절대경로 / travel.do

~ do 요청이다 ! web.xml 에서 do 요청은 DispatcherServlet 에서 처리하라고 했으니

 

 

 

 

[3-1] DispatcherServlet 

       - web.xml 에서 <init-param>의 값 읽어서 Properties 컬렉션에 담아놓고, 실재 경로 구하기

       - DispatcherServlet 에서 요청들어올때마다 해야하는 일 :

             맵핑파일 (propertyCollection)을 참고해서 직원을 지정해서 일을 시킨다

                 ㄴ 매핑파일이 들어있는 Properties 컬렉션에서 사용자의 URI(/tips/book.do)에 해당하는

                     직원 Controller(BookController)를 구해서,

                     직원 Controller에게 일시킨다(직원 Controller의 메서드 호출)

                          => 그리고 나서, 결과를 리턴 받아서 해당 뷰 페이지로 포워딩시킨다

public void init(ServletConfig config) throws ServletException {
		//매핑 파일을 읽어서 Properties 컬렉션에 담아 놓는다
		//web.xml에서 <init-param>의 값 읽기-CommandPro.properties 파일
		String configFile
			=config.getInitParameter("configFile"); //=>/config/CommandPro.properties
		System.out.println("configFile="+configFile);
		
		//매핑 파일의 실제 경로 구하기
		String realPath
		=config.getServletContext().getRealPath(configFile);
		System.out.println("realPath="+realPath+"\n");
		
		props=new Properties();
		FileInputStream fis=null;
		try {
			fis=new FileInputStream(realPath);
			props.load(fis);
			//=> CommandPro.properties파일의 정보를 Properties객체에 저장
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(fis!=null) fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

실재경로 구하는 두가지 방법

1. application.getrealPath

2. config.getServletcontext

 

한번만 해도되는 일

web.xml 매핑

디스패쳐서블릿

컨트롤러 인터페이스

 

매번 해야될 일

jsp(요청페이지+뷰페이지) 

해당 컨트롤러 클래스

매핑파일

 

 

 

 

[ 3-2 ] DispatcherServlet 

  - 매핑파일이 들어있는 Properties 컬렉션에서 사용자의 URI(/tips/book.do)에 해당하는 직원찾기

  - travelForm2.jsp에서 request 로 전송된 URI 를 받아서 contextpath 를 제거한다. 

     - /mymvc/tips/travel.do => /tips/travel.do

String uri=request.getRequestURI(); //=> /mymvc/tips/travel.do
		System.out.println("uri="+uri);
		
		//명령어 => contextpath 제거 : /tips/travel.do
		String ctxPath=request.getContextPath(); //=> /mymvc		
		if(uri.indexOf(ctxPath)==0) {
			uri=uri.substring(ctxPath.length()); //=> /tips/travel.do
		}
		
		System.out.println("ctxPath="+ctxPath+", 명령어:"+ uri);

 

 

[ 3-3 ] DispatcherServlet 

  - contextpath 를 제거한 URI 는 1번에서 property 에 저장된 매핑파일로가서 해당요청을 처리할 클래스를 찾는다.

     찾아서 변수 val 에 저장

  = > travel.do 를 처리할 클래스는 TravelController2 인것을 확인할 수 있음

        이때 TravelController2 Controller 인터페이스를 implement 한것이다. 

		//매핑파일
		//=>/tips/travel.do=com.tips.controller.TravelController2
		//key: /tips/travel.do,  value : TravelController2
		String val = props.getProperty(uri);
		System.out.println("명령어 처리 클래스:"+ val);

 

 

 

[ 3-4 ] DispatcherServlet 

가져온 String val을 Class로 변환하고 이것을 Controller 인터페이스로 다운캐스팅을 해서 클래스 객체생성을 한다.

그리고 해당 클래스의 메서드를 호출해서 받아온 값을 viewpage 변수에 저장

try {
			Class commandClass= Class.forName(val); //String=>Class
			//=> 해당 문자열을 클래스로 만든다.
			
			Controller controller = (Controller) commandClass.newInstance();
			//=> 해당클래스의 객체를 생성
			
			//명령어 처리 클래스의 메서드 호출
			String viewPage=controller.requestProcess(request, response);
			System.out.println("viewPage="+viewPage+"\n");

여기서 호출한 메서드는 다음과 같다 ▽

 

 

TravelController2 클래스의 requestProcess 메서드 호출

                                        ㄴ 에서 TravelExpert 클래스의 getTip 메서드 호출

public class TravelController2 implements Controller {

	@Override
	public String requestProcess(HttpServletRequest request, HttpServletResponse response) throws Throwable {
		//1
		String city=request.getParameter("city");

		//2
		TravelExpert model = new TravelExpert();
		String result=model.getTip(city);

		//3
		request.setAttribute("result", result);

		String viewPage="/tips/travelResult.jsp";
		return viewPage;
	}
public class TravelExpert {
	public String getTip(String city) {
		String result="";
		if(city.equals("강화")) {
			result="석모도";
		}else if(city.equals("강릉")) {
			result="정동진";
		}else if(city.equals("해남")) {
			result="땅끝마을";
		}else if(city.equals("거제")) {
			result="외도";
		}
		
		return result;
	}

  => 컨트롤러인 TravelFormController2 가 모델인 TravelExpert 에 의뢰한 과정

 

 

 

[ 3-5 ] DispatcherServlet 

if(controller.isRedirect()) {  //redirect
				System.out.println("redirect!\n");
				response.sendRedirect(ctxPath+viewPage); //=>/mymvc + /abc.jsp
			}else {  //forward
				//뷰페이지로 포워드
				System.out.println("forward!");
				
				RequestDispatcher dispatcher
				=request.getRequestDispatcher(viewPage);
				dispatcher.forward(request, response);				
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (Throwable e) {
			e.printStackTrace();
		}

forward 방식이 아닌 일반흐름을 redirect 라고 한다.

 

 

 

정리 : form 에서 do 로 요청을 하면 DispatcherServlet 으로 이동

DispatcherServlet 에서 Controller 메서드 호출해서 값을 받은 후에 뷰로 보낸다

 

 

 

 

DispatcherServlet 조각모음

package com.controller;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
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("/DispatcherServlet")
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    
	private Properties props;
	
	//해당 서블릿이 요청될때 최초로 한번만 호출되는 메서드
	@Override
	public void init(ServletConfig config) throws ServletException {
		//매핑 파일을 읽어서 Properties 컬렉션에 담아 놓는다
		//web.xml에서 <init-param>의 값 읽기-CommandPro.properties 파일
		String configFile
			=config.getInitParameter("configFile"); //=>/config/CommandPro.properties
		System.out.println("configFile="+configFile);
		
		//매핑 파일의 실제 경로 구하기
		String realPath
		=config.getServletContext().getRealPath(configFile);
		System.out.println("realPath="+realPath+"\n");
		
		props=new Properties();
		FileInputStream fis=null;
		try {
			fis=new FileInputStream(realPath);
			props.load(fis);
			//=> CommandPro.properties파일의 정보를 Properties객체에 저장
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(fis!=null) fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		requestPro(request, response);
	}

	protected void doPost(HttpServletRequest request, 
			HttpServletResponse response) 
					throws ServletException, IOException {
		requestPro(request, response);	
	}

	private void requestPro(HttpServletRequest request, 
			HttpServletResponse response) 
					throws ServletException, IOException{
		//매핑파일을 참고해서 직원을 구해서 일시킨다
		
		//매핑파일이 들어있는 Properties 컬렉션에서 사용자의 URI(/tips/book.do)에 해당하는
		//직원 Controller(BookController)를 구해서, 직원 Controller에게 일시킨다
		//(직원 Controller의 메서드 호출) 
		//=> 그리고 나서, 결과를 리턴 받아서 해당 뷰 페이지로 포워딩시킨다
		
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		
		//1. 요청 URI 에서 명령어 추출
		//URI 읽어오기
		String uri=request.getRequestURI(); //=> /mymvc/tips/travel.do
		System.out.println("uri="+uri);
		
		//명령어 => contextpath 제거 : /tips/travel.do
		String ctxPath=request.getContextPath(); //=> /mymvc		
		if(uri.indexOf(ctxPath)==0) {
			uri=uri.substring(ctxPath.length()); //=> /tips/travel.do
		}
		
		System.out.println("ctxPath="+ctxPath+", 명령어:"+ uri);
		
		//매핑파일
		//=>/tips/travel.do=com.tips.controller.TravelController2
		//key: /tips/travel.do,  value : TravelController2
		String val = props.getProperty(uri);
		System.out.println("명령어 처리 클래스:"+ val);
		
		try {
			Class commandClass= Class.forName(val); //String=>Class
			//=> 해당 문자열을 클래스로 만든다.
			
			Controller controller = (Controller) commandClass.newInstance();
			//=> 해당클래스의 객체를 생성
			
			//명령어 처리 클래스의 메서드 호출
			String viewPage=controller.requestProcess(request, response);
			System.out.println("viewPage="+viewPage+"\n");
			
			if(controller.isRedirect()) {  //redirect
				System.out.println("redirect!\n");
				response.sendRedirect(ctxPath+viewPage); //=>/mymvc + /abc.jsp
			}else {  //forward
				//뷰페이지로 포워드
				System.out.println("forward!");
				
				RequestDispatcher dispatcher
				=request.getRequestDispatcher(viewPage);
				dispatcher.forward(request, response);				
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (Throwable e) {
			e.printStackTrace();
		} 

	}

}

 

'Spring' 카테고리의 다른 글

[jsp] 모델2 기반의 MVC 패턴 게시판의 흐름  (0) 2022.05.22
회원가입  (0) 2022.05.19
[jsp] 에러  (0) 2022.05.17
[jsp] 쿠키 / 세션  (0) 2022.05.16
[jsp] 내장객체, 액션태그,자바빈  (0) 2022.05.13