본문 바로가기
👨‍💻 2. 웹개발_Back end/2-4 JSP & Servlet

[JSP & Servlet] 6장 미니 MVC 프레임워크 만들기 (1) 프런트 컨트롤러

by 달님🌙 2021. 10. 18.
반응형

 

6장 개요

 

1) 스프링 MVC를 모방한 간단한 MVC 프레임워크 만들어 보기

2) 스프링 프레임워크의 구동 원리와 내부 구조를 이해하기

3) 디자인 패턴 적용하는 방법과 오픈 소스 라이브러리를 사용하는 방법을 경험하기 

4) 리플렉션 API 사용법 익히기

5) 애노테이션을 정의하고 사용하는 방법 익히기

 

6.1 프런트 컨트롤러의 도입

 

1. 프런트 컨트롤러 도입 전

 

 

 

2. 컨트롤러 역할

 

 

3. 프런트 컨트롤러가 하는 일

 

 

4. 프런트 컨트롤러 만들기

- 프런트 컨트롤러의 클래스 이름은? DispatcherServlet

 

- 클라이언트 요청을 받아야 하기 때문에 서블릿이어야 함

- 페이지 컨트롤러를 실행하기 전에 공통 작업을 처리해야 하기 때문에, 요청 URL의 규칙을 정의할 필요 있음

 

 

- 즉 .do 접미사가 붙은 요청이 들어오면 DispatcherServlet에게 보냄

//기존의 회원 목록 요청 URL
http:localhost:9999/web05/member/list
//변경 후 회원 목록 요청 URL
http:localhost:9999/web05/member/list.do

 

- .do 로 끝나는 URL 요청을 처리하게 하려면, 서블릿 선언에 URL 매핑 정보를 설정해야 함

 

5. 프런트 컨트롤러가 요청을 처리하는 과정

 

- 웹브라우저로부터 *.do 요청이 들어오면, URL에서 서블릿 경로를 추출함

String servletPath = request.getServletPath();

- 서블릿 경로에 해당하는 페이지 컨트롤러를 찾아 실행을 위임함

 

 

- 페이지 컨트롤러는 작업을 마친 후, JSP URL 또는 리다이렉트 URL을 리턴함

 

- 프런트 컨트롤러는 페이지 컨트롤러가 알려준 JSP로 실행을 위임함

 

- 만약 페이지 컨트롤러가 리턴한 것이 리다이렉트 URL이라면, 리다이렉트로 응답을 처리함

 

6. DispatcherServlet 실습

 

- DispatcherServlet에 위임하여 공통 영역 작업을 수행하도록 함

- 서블릿 별로 URL이 매핑되어있는데 이를 DispatcherServlet라는 프론트컨트롤러를 통해서 메소드로 변경

 

DispatcherServlet.java

package spms.servlets;

import java.io.IOException;

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;

import spms.vo.Member;

/**
 * Servlet implementation class DispatcherServlet
 */
//모든 .do url 호출에 대한 처리를 프론트컨트롤러인 Dispatcher에서 처리
/*
 * 1) 의미 : tomcat으로부터 바로 제어 컨트롤러를 전송하는 방식
 * 			-> tomcat은 FrontController로 요청을 전송
 * 			   FrontController에서 각 PageController 분기해서 처리하도록
 * 			   FrontController : DispatcherServlet
 * 			   BackController(PageController) : 각 페이지 별 서블릿
 * 
 * 2) 이유 : 공통된 중복코드를 한 곳에 모아서 관리하기 편하게 하기 위함 -> 프레임워크의 기초 개념
 *			FrontController만 HttpServlet을 상속받고
 *			PageController들은 일반 자바 클래스로 변환
 *
 * 3) FrontController의 역할
 *	  3-1) 요청에 따른 페이지별 분기 처리
 *	  3-2) 페이지 컨트롤러로 전송될 VO 객체 생성
 *	  3-3) 서블릿/JSP 페이지 이동 처리
 *	  3-4) PageController에서 발생하는 모든 예외 처리
 *
 * 4) 장점
 * 	  4-1) FrontController만 HttpServlet을 상속받기 때문에 다른 WAS로 이식할 때 FrontController만 수정하면 됨
 * 	  4-2) 브라우저에 노출하고 싶지 않은 페이지 감춤
 * 	  4-3) 공통역할을  FrontController에 모아놓기 때문에 자동화(Framework화)하기 편함
 * 
 */

@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");
		
		//분기 처리를 위한 servlet(요청url) 경로 얻음
		String servletPath = request.getServletPath();
		try {
			//서블릿 경로에 따른 페이지컨트롤러 경를 담을 변수
			String pageControllerPath = null;

			if("/member/list.do".equals(servletPath)) {
				pageControllerPath = "/member/list";
			} else if("/member/add.do".equals(servletPath)) {
				pageControllerPath = "/member/add";
				
				//새로운 입력값이 있으면 doPost로, 없으면 doGet으로 처리
				if(request.getParameter("email") != null) {
					request.setAttribute("member", new Member()
							.setEmail(request.getParameter("email"))
							.setPassword(request.getParameter("password"))
							.setName(request.getParameter("name")));		
				}
			} else if("/member/update.do".equals(servletPath)) {
				pageControllerPath = "/member/update";
				
				//새로운 입력값이 있으면 doPost로, 없으면 doGet으로 처리
				if(request.getParameter("email") != null) {
					request.setAttribute("member", new Member()
							.setNo(Integer.parseInt(request.getParameter("no")))
							.setEmail(request.getParameter("email"))
							.setPassword(request.getParameter("password"))
							.setName(request.getParameter("name")));		
				}
			} else if("/member/delete.do".equals(servletPath)) {
				pageControllerPath = "/member/delete";
			} else if("/auth/login.do".equals(servletPath)) {
				pageControllerPath = "/auth/logout";
			}		
			
			//페이지컨트롤러로 위임
			RequestDispatcher rd = request.getRequestDispatcher(pageControllerPath);
			rd.include(request, response);
			
			
			//페이지컨트롤러에서 반환받은 JAP페이지로 위임
			String viewUrl = (String) request.getAttribute("viewUrl");
			
			//반환받은 값에 redirect가 포함되어 있으면 바로 페이지 이동
			if(viewUrl.startsWith("redirect:")) {
				response.sendRedirect(viewUrl.substring(9));
				return;
			} else {
				rd = request.getRequestDispatcher(viewUrl);
				rd.include(request, response);
			}
		} catch(Exception e) {
			e.printStackTrace();
			request.setAttribute("error", e);
			RequestDispatcher rd = request.getRequestDispatcher("/Error.jap");
			rd.forward(request, response);
		}
	}
}

 

MemberList.jsp (.do 붙이기)

<jsp:include page="/Header.jsp"/>
	<h1>회원 목록</h1>
	<p><a href="add.do">신규 회원</a></p>
	<!-- memberList라는 객체를 데이터 저장소에서 꺼냄
	     foreach문에서 memberList에 담겨있는 내용을 member라는 변수로 담아서 하나씩 사용하겠다 -->
	<c:forEach var="member" items="${memberList }">
	${member.no },
	<a href="update.do?no=${member.no }">${member.name }</a>,
	${member.email },
	${member.createDate }
	<a href="delete.do?no=${member.no }">삭제</a><br>
	</c:forEach>

 

MemberAddServlet.java

package spms.servlets;

import java.io.IOException;
import java.sql.Connection;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import spms.dao.MemberDAO;
import spms.vo.Member;

/**
 * Servlet implementation class MemberAddServlet
 */
@WebServlet("/member/add")
//HttpServlet은 GenericServlet을 상속받은 클래스
//service() 메소드를 호출방식에 따라 doGet(), doPost(), doPut(), doDelete()로 분리해놓음
public class MemberAddServlet extends HttpServlet {
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	//url에 주소 직접 입력 후 접속, 링크로 걸려있는 주소로 접속 -> get방식
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		request.setAttribute("viewUrl", "/member/MemberForm.jsp");
	}
	
	//입력폼에 입력된 정보를 submit할때 method 방식이 post이므로
	//doPost에서 데이터 입력 처리
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		ServletContext sc = this.getServletContext();
		
		try {
			MemberDAO memberDAO = (MemberDAO)sc.getAttribute("memberDAO");
			
			int result = memberDAO.insert((Member)request.getAttribute("member"));
			//sendRedirect 밑의 결과 값 출력 안하고 바로 /member/list로 이동
			//쿼리가 성공했을 경우 list페이지로
			if(result == 1) {
				request.setAttribute("viewUrl", "/redirect:list.do");
			}//실패했을 경우 Error페이지로
			else {
				RequestDispatcher rd = request.getRequestDispatcher("Error.jsp");
				rd.forward(request, response);
			}
		} catch(Exception e) {
			throw new ServletException(e);
		}
	}
}

 

MemberForm.jsp (add.do로 변경)

<form action="add.do" method="post">

 

MemberUpdateServlet.java

package spms.servlets;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import spms.dao.MemberDAO;
import spms.vo.Member;

/**
 * Servlet implementation class MemberUpdateServlet
 */
@WebServlet("/member/update")
public class MemberUpdateServlet extends HttpServlet {
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub		

		//서블릿 컨텍스트 객체 생성
		ServletContext sc = this.getServletContext();
		
		try {
			MemberDAO memberDAO = (MemberDAO)sc.getAttribute("memberDAO");
			
			Member member = memberDAO.selectOne(Integer.parseInt(request.getParameter("no")));
			
			request.setAttribute("member", member);
			
			request.setAttribute("viewUrl", "/member/MemberUpdateForm.jsp");
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		
		//서블릿 컨텍스트 객체 생성
		ServletContext sc = this.getServletContext();
		
		try {
			MemberDAO memberDAO = (MemberDAO)sc.getAttribute("memberDAO");
			
			int result = memberDAO.update((Member)request.getAttribute("member"));
			
			if(result == 1) {
				request.setAttribute("viewUrl", "redirect:list.do");
			} else {
				RequestDispatcher rd = request.getRequestDispatcher("/Error.jsp");
				rd.forward(request, response);
			}
		} catch(Exception e) {
			throw new ServletException(e);
		}
	}

}

 

MemberUpdateForm.jsp(.do 붙이기)

<form action="update.do" method="post">
    번호 : <input type="text" name="no" value="${member.no }" readonly><br>
    이름 : <input type="text" name="name" value="${member.name }"><br>
    이메일 : <input type="text" name="email" value="${member.email }"><br>
    가입일 : ${member.createDate }<br>
    <input type="submit" value="저장">
    <input type="button" value="삭제" onclick="location.href='delete.do?no=${member.no }';">
    <input type="button" value="취소" onclick="location.href='list.do';">
</form>

 

MemberDeleteServlet

package spms.servlets;

import java.io.IOException;
import java.sql.Connection;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import spms.dao.MemberDAO;

/**
 * Servlet implementation class MemberDeleteServlet
 */
@WebServlet("/member/delete")
public class MemberDeleteServlet extends HttpServlet {
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub		
		try {
			ServletContext sc = this.getServletContext();
			
			MemberDAO memberDAO = (MemberDAO)sc.getAttribute("memberDAO");
			
			int result = memberDAO.delete(Integer.parseInt(request.getParameter("no")));
			
			if(result == 1) {
				request.setAttribute("viewUrl", "redirect:list.do");
			} else {
				RequestDispatcher rd = request.getRequestDispatcher("/Error.jsp");
				rd.forward(request, response);
			}
		} catch(Exception e) {
			throw new ServletException(e);
		}
	}
}

 

LoginServlet.java

- request.setAttribute()로 수정

package spms.servlets;

import java.io.IOException;
import java.sql.Connection;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import spms.dao.MemberDAO;
import spms.vo.Member;

/**
 * Servlet implementation class LoginServlet
 */
@WebServlet("/auth/login")
public class LoginServlet extends HttpServlet {
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//get 방식으로 요청이 오면 로그인 페이지로 이동
		request.setAttribute("viewUrl", "/auth/LoginForm.jsp");
	}

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

		try {
			ServletContext sc = this.getServletContext();
			
			MemberDAO memberDAO = (MemberDAO)sc.getAttribute("memberDAO");
			
			Member member = memberDAO.exist(request.getParameter("email"), request.getParameter("password"));
						
			//로그인 성공 시
			if(member != null) {
				HttpSession session = request.getSession();
				session.setAttribute("Member", member);
				request.setAttribute("viewUrl", "redirect:../member/list.do");
			} //로그인 실패 시(member객체가 null일 떄)
			else {
				request.setAttribute("viewUrl", "/auth/LoginFail.jsp");
			}
		} catch(Exception e) {
			throw new ServletException(e);
		}
	}

}

 

LoginForm.jsp와 LoginFail.jsp 파일 .do로 방식 변경

login -> login.do

 

LogoutServlet.java 

request.setAttribute("viewUrl", "redirect:login.do");

 

실행 화면

 

 

반응형

댓글