열심히 끝까지

디바이스 융합 자바(Java) day51 - FrontController 패턴,Request Dispatcher 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(수업내용)

디바이스 융합 자바(Java) day51 - FrontController 패턴,Request Dispatcher

노유림 2022. 8. 23. 18:24

<%@ %>
---------------------
<%@ tag %>
<%@ page %>

<% %>
---------------------
<% out.println(); %>

<%= %>
<jsp: >

V : EL식 / 커스텀태그 / JSTL
M : 리스너 / 트랜잭션
C : 필터 FrontController(FC)

[ C - FrontController 패턴 ]
MVC 패턴 + FC 패턴 => MVC 모델 2



MVC 패턴 : JDBCUtil을 이용해서 db와 관련된 일을 해냄 = ~.java로 작업



M : .java 
V : .jsp -> JAVA 코드가 없어야 함
C : ctrlB.jsp | ctrlM.jsp 
   >> .jsp에서 작업한 C는 결합도가 높음...
         -> 분할 관리 => FC 서블릿 파일을 생성해서 관리
         -> .jsp vs .java
       = 분할 관리 시, .java 이용하는 것이 맞음!
         : setProperty 액션을 일일히 해야되나?
                >> 네... 일일히 써야 함..
                     Spring 프레임워크에서 자동매핑 지원해줌!
         : request.Xxx() 사용해야되는데???
                >> Servlet(서블릿) 파일을 이용할 예정이라 request 사용 가능!

   ★ 낮은 결합도 & 높은 응집도 => '유지보수에 용이'한 코드 ★


>> FrontController 에서...

public FrontController() {  // 기본 생성자
        super();
        // TODO Auto-generated constructor stub
}

- 서블릿들은 기본 생성자 필수! 
   > ★ 기본 생성자가 필수인 이유 
       >> FrontContrller fc = new FrontController();를 한번도 쓴 적이 없음
           .. 객체화를 하지 않았는데, 메서드를 사용할 수 있었다...??
           >> 서블릿 컨테이너(==객체를 관리하는 것) 
                 == 웹 서버 
                 == 톰캣이 서블릿을 객체화해주고 있었음!


>> 기본 작업

package ctrl;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class FrontController
 */
@WebServlet("*.do") // *.do 요청을 수행하면 해당 어노테이션(애노테이션)에 의해 FC로 오게 됨!!!
public class FrontController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public FrontController() { // 서블릿들은 기본 생성자 필수! 
    	// ★ 기본 생성자가 필수인 이유 >> FrontContrller fc = new FrontController();를 한번도 쓴 적이 없음
    	// 객체화를 하지 않았는데, 메서드를 사용할 수 있었다...??
    	// 서블릿 컨테이너(==객체를 관리하는 것) == 웹 서버 == 톰캣이 서블릿을 객체화해주고 있었음!
    	
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		actionDO(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		actionDO(request, response);
	}
	
	// 직접 만드는 액션
	private void actionDO(HttpServletRequest request, HttpServletResponse response) {
		String uri=request.getRequestURI();
		System.out.println(uri);
	}

}

 

index.jsp---------------------------

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	response.sendRedirect("index.do"); // ctrlB.jsp?action=main
%>

>> 실행 시
- 화면은 아무것도 안뜸 

- 하지만 콘솔은?

 

FrontController.java의 actionDO------------------

private void actionDO(HttpServletRequest request, HttpServletResponse response) {
	String uri=request.getRequestURI();
	String cp=request.getContextPath();
	System.out.println(uri);
	System.out.println(cp);
}

>> 실행결과

 

FrontController.java의 actionDO------------------

private void actionDO(HttpServletRequest request, HttpServletResponse response) {
	String uri=request.getRequestURI();
	String cp=request.getContextPath();
	String command=uri.substring(cp.length());
	System.out.println(uri);
	System.out.println(cp);
	System.out.println(command);
	
	if(command.equals("/index.do")) {
		// 메인 보여주는 C 블러와... 라고 요청
	}
}

>> 실행 결과

 

>> 사용자가 요청하면 그 요청에 맞는 Action 가져옴
/login.do        >> LoginAction
/main.do        >> MainAction
/logout.do      >> LogoutAction
/insertB.do      >> InsertBoardAction
/deleteR.do     >> DeleteReplyAction
.
.
.

XxxAction => 그냥 일반적인 Controller 역할의 클래스 파일(.java)
     >> 내부에는 execute(){} 메서드 존재
         execute(){
                 1. request 요청 정보로부터 데이터를 추출
                 2. vo 객체에 setter
                 3. dao 객체에 vo 전달
                 4. 결과값을 다음 V에게 전달
         }

>> ctrl.jsp 에서 하던 작업 순서
>> 2 -> 1 -> 3 -> 4

>> XxxAction에 있는 메서드가 있을 때 필요한 것
        : request, response가 반드시 필요함

         execute(request, response){
                 1. request 요청 정보로부터 데이터를 추출
                 2. vo 객체에 setter
                 3. dao 객체에 vo 전달
                 4. 결과값을 다음 V에게 전달
         }

>> 반환 타입이 어떤 경로, 어떤 방식으로 보내는가?
         : 두개를 동시에 보내지 못한다....
         >> 어떤 경로, 어떤 방식을 저장하는 클래스를 생성
                : ActionForward 라는 클래스 생성
                      : String 어떤 경로
                        boolean 어떤 방식

         ActionForward execute(request, response){
                 1. request 요청 정보로부터 데이터를 추출
                 2. vo 객체에 setter
                 3. dao 객체에 vo 전달
                 4. 결과값을 다음 V에게 전달
         }

>> 메서드를 강제하는 "인터페이스(추상 메서드)" 필요!!!
    


index.jsp---------------

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	response.sendRedirect("main.do"); // ctrlB.jsp?action=main
	// action이라는 파라미터를 쓰지 않아도 되기 때문에
	// 파라미터를 하나 덜 씀
%>

 

 

[ Request Dispatcher ] 
- Spring을 기반으로하는 Dispatcher이지만 
  Spring에서 쓰는 Dispatcher랑 똑같지는 않음 

 : 특정 자원에 처리를 요청하고,
   그 결과를 얻어오는 기능을 수행하는 클래스
 : 사용자(Client, 브라우저)로부터 오는 요청을 처리해서,
   그 결과를 설정된 페이지에 출력하는 역할

 ex ) RequestDispatcher dispatcher=request.getRequestDispatcher(forward.getPath());
        >> forward.getPath() : 어느 페이지로 갈지 언급해주는 부분
        >> dispatcher.forward(request, response); 
                : 타겟페이지(forward.getPath())(미리 작성해 놓은 인자)로 
                  request, response 객체를 전달하는 메서드
                : 페이지 제어권을 넘겨줌 -> 클라이언트가 응답을 확인할 수 있음

 

FrontController.java--------------------------------------

package ctrl;

import java.io.IOException;
import java.io.PrintWriter;

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;

/**
 * Servlet implementation class FrontController
 */
@WebServlet("*.do") // *.do 요청을 수행하면 해당 어노테이션(애노테이션)에 의해 FC로 오게 됨!!!
public class FrontController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public FrontController() { // 서블릿들은 기본 생성자 필수! 
    	// ★ 기본 생성자가 필수인 이유 >> FrontContrller fc = new FrontController();를 한번도 쓴 적이 없음
    	// 객체화를 하지 않았는데, 메서드를 사용할 수 있었다...??
    	// 서블릿 컨테이너(==객체를 관리하는 것) == 웹 서버 == 톰캣이 서블릿을 객체화해주고 있었음!
    	
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		actionDO(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		actionDO(request, response);
	}
	
	// 직접 만드는 액션
	private void actionDO(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		String uri=request.getRequestURI();
		String cp=request.getContextPath();
		String command=uri.substring(cp.length());
		System.out.println(uri);
		System.out.println(cp);
		System.out.println(command);
		
		ActionForward forward = null;
		if(command.equals("/main.do")) {
			// 메인 보여주는 C 블러와... 라고 요청
			try {
				forward = new MainAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/logout.do")){
			try {
				forward = new LogoutAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/login.do")){
			try {
				forward = new LoginAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/insert.do")){
			try {
				forward = new InsertMemberAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/insertB.do")){
			try {
				forward = new InsertBoardAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/insertR.do")){
			try {
				System.out.println("R들어옴");
				forward = new InsertReplyAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/deleteB.do")){
			try {
				forward = new DeleteBoardAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/deleteR.do")){
			try {
				forward = new DeleteReplyAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else if(command.equals("/fav.do")){
			try {
				forward = new FavAction().execute(request, response);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		/*
		if(forward==null) { // forward가 null이면 error 페이지로 가!
			forward=new ActionForward();
			forward.setPath("error/error.jsp");
			forward.setRedirect(false);
		}
		
		RequestDispatcher dispatcher=request.getRequestDispatcher(forward.getPath());
		try {
			dispatcher.forward(request, response);
			// : 타켓페이지(인자)로 request, response 객체를 전달하는 메서드
			// : 제어권을 넘겨줌 -> 클라이언트가 응답을 확인할 수 있음
		} catch (ServletException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		*/
		if(forward!=null) {
			// 디스패쳐 만들어서 타겟페이지로 이동
			if(forward.isRedirect()) {
				response.sendRedirect(forward.getPath());
			}
			else {
				RequestDispatcher dispatcher=request.getRequestDispatcher(forward.getPath());
				dispatcher.forward(request, response); // 정확하게 언급 했을 때 수행
			}
		}
		// 권장하지 않음(script는 jsp에서 쓰는것이 맞음)
		// alert창을 쓰고 싶으면 java가 아닌 서블릿에서 작성해야 함
		PrintWriter out = response.getWriter();
		out.println("<script>alert('요청처리 실패!');history.go(-1);</script>");
		
	}

}

InsertBoardAction.java-----------------------

package ctrl;

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

import board.BoardDAO;
import board.BoardVO;

public class InsertBoardAction implements Action{

	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
				
		BoardDAO dao = new BoardDAO();
		BoardVO vo = new BoardVO();
		
		vo.setMsg(request.getParameter("msg"));
		vo.setMid(request.getParameter("mid"));
		System.out.println("로그 : vo.mid값 = " + vo.getMid());
		
		if(dao.insert(vo)) {
			ActionForward forward= new ActionForward();
			forward.setPath("main.do");
			forward.setRedirect(true);
			return forward;
		}
		else {
			System.out.println("로그 : 글 추가 실패");
			throw new Exception("InsertB 오류");
		}
	}

}

DeleteBoardAction.java-----------------------

package ctrl;

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

import board.BoardDAO;
import board.BoardVO;

public class DeleteBoardAction implements Action{

	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ActionForward forward=null;
		
		BoardDAO dao = new BoardDAO();
		BoardVO vo = new BoardVO();
		
		vo.setBid(Integer.parseInt(request.getParameter("bid")));
		
		if(dao.delete(vo)) {
			forward = new ActionForward();
			forward.setPath("main.do");
			forward.setRedirect(false);
		}
		else {
			System.out.println("로그 : 글 삭제 오류");
			throw new Exception("DeleteB 오류");
		}
		
		return forward;
	}

}

mainAction.java-----------------------

package ctrl;

import java.util.ArrayList;

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

import board.BoardDAO;
import board.BoardSet;
import board.BoardVO;

public class MainAction implements Action{

	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 1. 요청정보 인코딩을 안했다면 꼭 해줄 것
		// request.setCharacterEncoding("UTF-8");
		// response.setCharacterEncoding("UTF-8");
		
		// 2. 로직 처리 
		// 2-1. Board 필요
		BoardDAO dao= new BoardDAO();
		BoardVO vo = new BoardVO();
		
		// 2-2. 요청정보 세팅 - main은 cnt만 받아와서 세팅하면 됨
		// vo.setCnt(Integer.parseInt(request.getParameter("cnt")));
		String paramCnt=request.getParameter("cnt");
		if(paramCnt==null) {// cnt 파라미터에 정보가 있어?
			vo.setCnt(2);
	 	}
		else {
			vo.setCnt(Integer.parseInt(request.getParameter("cnt")));
		}
		
		ArrayList<BoardSet> datas = dao.selectAll(vo);
		request.setAttribute("datas", datas);
		request.setAttribute("cnt", vo.getCnt());
		
		// 3. 정보 보내주기
		ActionForward forward = new ActionForward();
		forward.setPath("/main.jsp");
		forward.setRedirect(false);
		
		return forward;
	}
	
}
/*
 	ArrayList<BoardSet> datas = bDAO.selectAll(bVO);
	request.setAttribute("datas", datas);
	request.setAttribute("cnt", bVO.getCnt());
	pageContext.forward("main.jsp"); 
 
*/