WEB JAVA SPRING/etc

MVC model2 //DispatcherServlet

sshhhh 2023. 8. 28. 14:22

 

 

Model

데이터를 처리하는 영역(어떠한 동작을 수행하며 public 함수로만 이루어진다.)

 

View

컨트롤러의 처리결과를 화면에 생성

 

Controller

클라이언트의 요청 처리

 

 

사용하는 이유?

사용자 인터페이스로부터 비즈니스 로직을 분리한다. (=개발자, 웹 퍼블리셔의 영역 분리 가능)

 > 애플리케이션의 시작적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 고칠 수 있다.

 > view 교체, 변경 쉬워서 유지보수가 유용하다.

 

 

 


 

 

service

핵심 비즈니스 로직 구현

 

 

repository (= DAO : Data Access Object) 

- Spring data JPA방식

- 도메인 객체를 DB에 접근하여 저장하고 관리 (저장소)

- interface로 사용 

 

 

domain (= VO : Value Object , DTO : Data Transfer Objec , model)

비즈니스 도메인 객체, ex) 회원,주문,상품.. 주로 DB에 저장하고 관리됨 (엔티티)

 

 




디스패처 서블릿(DispatcherServlet)

유일한 서블릿 클래스로서 모든 클라이언트의 요청을 가장 먼저 처리하는 Front Controller(클라이언트 요청의 진입점)

웹 애플리케이션의 모든 클라이언트 요청을 처리하는 역할을 수행

 

<순서>
1. **클라이언트 요청 처리**

클라이언트가 보낸 요청이 DispatcherServlet에 도착, 어떤 컨트롤러가 요청을 처리할지를 결정

2. **HandlerMapping 사용**

클라이언트의 요청을 처리할 Controller(java)를 매핑 (어떤 컨트롤러를 선택할지를 결정)

+원하는 beans properties를 찾아오는 역할 수행


3. **컨트롤러 호출**

선택된 컨트롤러를 호출하여 실제 비즈니스 로직을 수행


4. **뷰 선택 및 데이터 전달**

컨트롤러가 처리한 결과데이터를 뷰(View)에 전달

5. **응답 생성**

뷰는 전달받은 데이터를 기반으로 클라이언트에게 보여줄 응답을 생성

이 응답은 HTML, CSS, JavaScript 등을 사용하여 웹 페이지로 구성되며,

클라이언트가 브라우저를 통해 볼 수 있는 형태로 제공


- **Bean Properties**

빈(Bean) 객체의 설정 정보를 담은 파일,  각 빈 객체의 이름과 해당하는 클래스, 속성 등의 설정 정보를 포함

 

1. 서블릿은 클라이언트의 모든 요청만 수신
2. 실제 비즈니스 로직은 자바 코드로 구현한 컨트롤러에서 처리
3. 데이터베이스에 접근하여 필요한 정보를 가져옴
 
 
 

dispacherservlet

package kr.co.mlec.controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 유일한 서블릿 클래스 : 클라이언트의 요청을 가장 먼저 처리
public class DispatcherServlet extends HttpServlet {		
	
	private HandlerMapping mappings = null;
	/*HandlerMapping: 클라이언트의 요청을 처리할 Controller(java)를 매핑
	                  beans properties를 찾아와야하니까
	*/  
	//매핑 :해당 값이 다른 값을 가리키도록 하는 것
	
	
	/*서블렛 요청 호출 순서
	 1.init :메소드 사용하여 초기화 작업 수행
	 2.service: 사용자 요청에 대한 실제 응답 처리
	 3.destroy
	*/
	
	//servlet-> HandlerMapping
	
	@Override       //config :  환경 설정 ,  예외를 던져
	public void init(ServletConfig config) throws ServletException {
		
		String propLoc =config.getInitParameter("propLocation");		
		mappings = new HandlerMapping(propLoc);
	}
	
	
	
	@Override
	                      
	//controller 인터페이스 재정의  + 실제응답처리
	                      //request  요청 : uri 
	                      //responce 응답 : contextPath 받아옴
	public void service(HttpServletRequest request, 
					    HttpServletResponse response) 
					throws ServletException, IOException {
		//uri: identify  
		                    
		String uri = request.getRequestURI();  
		String context = request.getContextPath(); 
		//응답을 받아와야하니까 get,  url주소를 가져오는 함수
		
		uri = uri.substring(context.length()); //문자 추출
		System.out.println("요청 URI : " + uri); //가져온 uri 출력
        
		
		try {	//session 때매?
			Controller control = mappings.getController(uri); 
		    // 인터페이스  변수    = 요청한 uri 가져오려고 매핑+get
			
			String callPage = control.handleRequest(request, response);
			// callPage : 인터페이스 control에서 재정의, uri 정보 담겨있음
			
			//servlet이 jsp에 넘겨주려고 forward ->jsp 주소 알려줌
			//uri 넘겨줄거임
			RequestDispatcher dispatcher = request.getRequestDispatcher(callPage);
			dispatcher.forward(request, response); 
			
		} catch(Exception e) {
			e.printStackTrace();
			throw new ServletException(e);
		}
		
	}
}

 

request.getContextPath() : 프로젝트 path만 얻어온다.

예) http://localhost:8081/board /list.jsp

return: /board

 

request.getRequestURI() : 프로젝트와 파일경로까지 얻어온다.

예) http://localhost:8081/board/list.jsp

return: /board/list.jsp

 
 
 
 
HandlerMapping
package kr.co.mlec.controller;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class HandlerMapping {	
	            // 원하는 beans properties를 찾아오는 역할을 수행 ->매핑
               //키    ,    값
	private Map<String, Controller> mappings = null;
	
	                      ///board/list.do 가져와
	public HandlerMapping(String propLoc) {
		
		//Properties 주요 클래스 :Key = Value 형태로 된 파일 가져와
		Properties prop = new Properties();
		mappings = new HashMap<>(); 
		
		
		try {
			//InputStream is = new FileInputStream("D:\\Lecture\\web-workspace\\Mission-Web-MVC\\bean.properties");
			InputStream is = new FileInputStream(propLoc);
			//inputStream : 데이터를 읽어옴
			prop.load(is);
	
			Set<Object> keys = prop.keySet();	//keySet: key의 값만 출력
			for(Object key : keys) { //keys값 key에 넣어서 죄다 출력
				
				String className = prop.getProperty(key.toString()); //key 객체타입이라 형변환
				System.out.println(key + " : " + className);
				
				Class<?> clz = Class.forName(className);
				//클래스의 정보를 얻기위한 클래스 
				//forName():물리적인 클래스 파일명을 인자로 넣어주면 이에 해당하는 클래스를 반환
				mappings.put(key.toString(), (Controller)clz.newInstance());
			
			}
			
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		
	}
	
	public Controller getController(String uri) {
		return mappings.get(uri);
	}}

 

 

bean.properties

요청(String)  =   응답(Controller)
/board/list.do=kr.co.mlec.controller.BoardListController
/board/writeForm.do=kr.co.mlec.controller.BoardWriteFormController

 


 

interface Controller

인터페이스를 중간에 두는 이유는 개발 코드를 수정하지 않고, 사용하는 객체를 변경할 수 있도록 하기 위해서

package kr.co.mlec.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface Controller {

	String handleRequest(HttpServletRequest request, HttpServletResponse response)throws Exception;
	
}

 

 

BoardListController

package kr.co.mlec.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.co.mlec.board.vo.BoardVO;

//  /board/list.do (전체리스트조회)호출되었을 때
//  1. 비즈니스 로직 수행 (tbl_board에서 전체게시글 조회)
//  2. servlet에게 forward 시킬 jsp/board/list/jsp 알려줌

public class BoardListController implements Controller {	
	//controller 인터페이스 상속 받아 안의 내용 사용 

	@Override
	public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception{		//String으로 받는 이유는 jsp주소값으로 받기 때문에 
		
		List<BoardVO> list = new ArrayList<>();
		list.add(new BoardVO("aaa","bbb"));
		list.add(new BoardVO("ccc","ddd"));
		list.add(new BoardVO("eee","fff"));
		
		request.setAttribute("list", list); 	
		//공유영역인 request에 등록해 준다.
		return "/jsp/board/list.jsp";
	}
	
}

 

BoardWriteFormController

package kr.co.mlec.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class BoardWriteFormController implements Controller{

	@Override
	public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception{
		
		return "/jsp/board/write.jsp";	//절대경로
	}
}

 


 

list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>전체게시글</h2>
	<table border="1">
		<tr>
			<th>제목</th>
			<th>작성자</th>
		</tr>
		<c:forEach items="${ list }" var="board">
			<tr>
				<td>${ board.title }</td>
				<td>${ board.writer }</td>
			</tr>
		</c:forEach>
	</table>
</body>
</html>