※ 모델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 |