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

[JSP & Servlet] 5장 MVC 아키텍처 (3) - 데이터 보관소

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

 

5.6 데이터 보관소

 

1. 생성과 소멸 시점

- 4가지의 보관소로 이루어짐

1) ServletContext : 시작될 때 만들어지고 종료될때 삭제가됨

2) HttpSession : 클라이언트의 요청이 들어왔을때 최초 생성되고 세션이 닫히면 삭제가 됨

3) ServletRequest : 클라이언트의 요청이 왔을때 생성되고 응답이 끝날 때 사라짐

4) JspContext  : jsp 페이지가 실행되는 동안에만 데이터를 사용할 수 있는 보관소로 지정됨

 

2. 웹 애플리케이션

1) ServletContext : 웹 애플리케이션 시작 시 준비됨 웹 애플리케이션 당 1개

2) HttpSession : 최초 요청 시 생성되고 세션이 무효화 되기 전까지 유지됨 세션 ID를 통해 사용자 별

3) ServletRequest : 매 요청 때마다 보관소가 생성되고 응답 전까지 유지됨, 포워드와 인클루드 서블릿끼리 데이터 공유할 때 적합

5) JspContext  : JSP 페이지를 실행하는 동안 존재함 태그 핸들러와 데이터를 공유할 때 사용

 

3. ServletContext 활용 전

 

- 이렇게 서블릿'마다' DB커넥션을 만들어주고 연결했음

 

4. ServletContext 활용 후

- 커넥션을 하나만 사용하도록 만듬

 

5. ServletContext 실습하기 ( _15_MVC_AppInit )

 

Servlet 파일 생성하기 - AppInitServlet.java

package spms.servlets;

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

import javax.servlet.ServletConfig;
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;

/**
 * Servlet implementation class AppinitServlet
 */

//웹 애플리케이션을 이용해서 서버를 여는 것이므로 URL매핑을 따로 지정해줄 필요가 없음
//@WebServlet("/AppInitServlet")
public class AppInitServlet extends HttpServlet {
	@Override
	public void init(ServletConfig config) throws ServletException {
		System.out.println("AppInitServlet 준비...");
		super.init(config);
		
		try {
			ServletContext sc = this.getServletContext();
			
			String driver = sc.getInitParameter("driver");
			String mySqlUrl = sc.getInitParameter("url");
			String id = sc.getInitParameter("username");
			String pwd = sc.getInitParameter("password");
			
			Class.forName(driver);
			Connection conn = DriverManager.getConnection(mySqlUrl, id, pwd);
			//servletcontext 데이터 보관소에 mysql 접속 객체를 저장
			sc.setAttribute("conn", conn);
		} catch(Exception e) {
			throw new ServletException(e);
		}
	}
	
	@Override
	public void destroy() {
		System.out.println("AppInitServlet 마무리...");
		super.destroy();
		
		//servletcontext 데이터 보관소에 저장되어 있는 mysql 접속 객체 꺼내옴
		Connection conn = (Connection)this.getServletContext().getAttribute("conn");
	
		try {
			if(conn != null && conn.isClosed() == false) {
				conn.close();
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}

 

web.xml

* URL매핑이 없어서 클라이언트가 요청을 할 수가 없음

* 클라이언트의 요청이 없어도 웹어플리케이션이 실행될 때 자동으로 서블릿이 생성되도록 함

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>_06_JDBCServlet</display-name>
  
  <!-- 컨텍스트 초기화 매개변수 -->
  <context-param>
  	<param-name>driver</param-name>
  	<param-value>com.mysql.jdbc.Driver</param-value>
  </context-param>
  <context-param>
  	<param-name>url</param-name>
  	<param-value>jdbc:mysql://localhost/studydb?serverTimezone=UTC</param-value>
  </context-param>
  <context-param>
  	<param-name>username</param-name>
  	<param-value>study</param-value>
  </context-param>
  <context-param>
  	<param-name>password</param-name>
  	<param-value>study</param-value>
  </context-param>
  
  <!-- AppInitServlet 선언 -->
  <servlet>
  	<servlet-name>AppInitServlet</servlet-name>
  	<servlet-class>spms.servlets.AppInitServlet</servlet-class>
  	<!-- 클라이언트의 요청이 없어도 웹어플리케이션이 실행될 때 자동으로 서블릿이 생성되도록 함 -->
  <load-on-startup>1</load-on-startup>
  </servlet>
  
  <!-- 필터 선언 -->
  <!-- <filter>
  	<filter-name>CharacterEncodingFilter</filter-name>
  	<filter-class>spms.filter.CharacterEncodingFilter</filter-class>
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>UTF-8</param-value>
  	</init-param>
  </filter>-->
  
  <!-- 필터 url 매핑 -->
  <!-- /* : 모든 url 요청에 적용 -->
  <!--<filter-mapping>
 	<filter-name>CharacterEncodingFilter</filter-name>
 	<url-pattern>/*</url-pattern> 
  </filter-mapping>-->
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

 

MemberListServlet.java 파일 수정 (Add 파일과 Update 파일도 마찬가지로 진행)

* mysql 서버 접속 정보 4줄 주석 처리

* try 구문 내에 DriverManager와 Class.forname 부분 주석 처리

* 대신 conn = (Connection)sc.getAttribute("conn"); 문장 추가

		ServletContext sc = this.getServletContext();
		
		//mysql 서버 접속정보
//		String driver = sc.getInitParameter("driver");
//		String mySqlUrl = sc.getInitParameter("url");
//		String id = sc.getInitParameter("username");
//		String pwd = sc.getInitParameter("password");
		
		try {
			// 1. MySQL 제어 객체를 로딩
			//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
//			Class.forName(driver);
			// 2. MySQL 연결
//			conn = DriverManager.getConnection(mySqlUrl, id, pwd);
			//servletcontext 데이터 보관소에 저장되어 있는 Connection 객체를 꺼내 씀
			conn = (Connection)sc.getAttribute("conn");
			// 3. sql문 객체 생성
			stmt = conn.createStatement();
			// 4. sql 전송 후 결과 값 리턴받기
			rs = stmt.executeQuery(sqlSelect);
			// 5. 결과를 브라우저로 전송
			response.setContentType("text/html;charset=UTF-8");
			ArrayList<Member> members = new ArrayList<Member>();

 

* servletcontext 데이터 보관소에 저장되어 있는 Connection 객체를 꺼내 씀

* 코드짜기가 훨씬 간편해짐 (코드 간소화)

 

6. 클라이언트 요청을 처리하지 않는 서블릿

 

7. 기존 서블릿 변경

 

8. HttpSession (로그인에 자주 사용됨)

 

 

 

* Tomcat 서버는 기본적으로 세션이 30분 뒤에 꺼지도록 설정이 되어있음

 

 

9. HttpSession 로그인, 로그아웃 실습하기 ( _16_MVC_Login_Logout )

실습1) 로그인 성공/실패

LoginServlet.java 파일 생성

package spms.servlets;

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

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.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 방식으로 요청이 오면 로그인 페이지로 이동
		RequestDispatcher rd = request.getRequestDispatcher("/auth/LoginForm.jsp");
		rd.forward(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//post 방식으로 요청이 오면 로그인 처리
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		String sqlLogin = "SELECT MNAME, EMAIL FROM MEMBERS WHERE EMAIL=? AND PWD=?";
		
		try {
			ServletContext sc = this.getServletContext();
			conn = (Connection)sc.getAttribute("conn");
			stmt = conn.prepareStatement(sqlLogin);
			stmt.setString(1, request.getParameter("email"));
			stmt.setString(2, request.getParameter("password"));
			rs = stmt.executeQuery();
			
			//로그인 성공 시
			if(rs.next()) {
				Member member = new Member()
										  .setEmail(rs.getString("EMAIL"))
										  .setName(rs.getNString("MNAME"));
				HttpSession session = request.getSession();
				session.setAttribute("Member", member);
				
				response.sendRedirect("../member/list");
			} //로그인 실패시
			else {
				RequestDispatcher rd = request.getRequestDispatcher("/auth/LoginFail.jsp");
				rd.forward(request, response);
			}
		} catch(Exception e) {
			throw new ServletException(e);
		} finally {
			try {
				if(rs != null) {
					rs.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

LoginForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인</title>
</head>
<body>
	<h2>사용자 로그인</h2>
	<form action="login" method="post">
		이메일 : <input type="text" name="email"><br>
		암호 : <input type="password" name="password"><br>
		<input type="submit" value="로그인"><br>
	</form>
</body>
</html>

 

LoginFail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Refresh" content="1; url=login">
<title>로그인 실패</title>
</head>
<body>
	<p>로그인 실패입니다. 이메일 또는 암호가 맞지 않습니다.
	잠시 후에 다시 로그인 화면으로 갑니다.</p>
</body>
</html>

 

MemberListServlet.java 파일 수정 (맨 아래 try-catch문 지울것)

finally {
			try {
				if(rs != null) {
					rs.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
//			try {
//				if(conn != null) {
//					conn.close();
//				}
//			} catch(Exception e) {
//				e.printStackTrace();
//			}
		}

 

실행 화면 (로그인 실패 화면) - 목록에 없는 이메일 입력

- 이 화면에서 1초만에 바로 다시 로그인 화면으로 이동하게됨

 

실행 화면 (로그인 성공 화면) - 목록에 있는 이메일 입력

- 목록에 있는 이메일로 로그인 하는 경우 회원 목록 페이지로 이동하게 됨

 

실습2) 헤더 우측에 로그인 정보 띄우기

Header.jsp 파일 수정

<%@ page import="spms.vo.Member" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//HttpSession 데이터 보관소에 저장된 member 객체 꺼내서 사용
	Member member = (Member)session.getAttribute("Member"); 
%>
<div style="background-color:#00008b; color:#ffffff; height:20px; padding:5px">
SPMS(Simple Project Management System)
<span style="float:right;">
	<%=member.getName() %>
	<a style="color:white;" href="<%=request.getContextPath() %>/auth/logout">로그아웃</a>
</span>
</div>

 

실행 화면

로그인하기
로그아웃 버튼 생김

 

실습3) HttpSession 무효화 - 로그아웃

LogoutServlet.java 파일 생성

package spms.servlets;

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;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class LogoutServlet
 */
@WebServlet("/auth/logout")
public class LogoutServlet 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
		HttpSession session = request.getSession();
		//세션 무효화 처리
		session.invalidate();
		
		response.sendRedirect("login");
	}
}

 

실행 화면

로그아웃 버튼 누르면?

 

다시 로그인 페이지로 이동하게됨

 

실습4) 회원 정보 삭제

MemberList.jsp

<%@ page import="spms.vo.Member"%>
<%@ page import="java.util.ArrayList" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 목록</title>
</head>
<body>
	<!-- jsp action tag 
		jsp:useBean, jsp:setProperty, jsp:getProperty, jsp:forward, jsp:include.....
		actiontag를 이용하면 jsp의 자바 소스를 줄일 수 있다 
	-->
	<jsp:include page="/Header.jsp"/>
	<h1>회원 목록</h1>
	<p><a href="add">신규 회원</a></p>
	<!-- servletrequest 데이터 보관소에서 memberList라는 객체를 꺼내옴 -->
	<!-- id : 사용할 객체 이름 -->
	<!-- scope : 어느 데이터 보관소에서 객체를 꺼내올지 결정 
				 request(servletrequest 데이터 보관소), 
				 session(HttpSession 데이터 보관소),
				 application(Servletcontext 데이터 보관소) -->
	<jsp:useBean id="memberList" 
				 scope="request" 
				 class="java.util.ArrayList" 
				 type="java.util.ArrayList<spms.vo.Member>"></jsp:useBean>
	<%
		//MemberListServlet에서 request.setAttribute로 전달한 결과 값 꺼내쓰기
		//ArrayList<Member> members = (ArrayList<Member>)request.getAttribute("memberList");
		for(Member member : memberList) {
	%>
	<%=member.getNo() %>,
	<a href="update?no=<%=member.getNo()%>"><%=member.getName() %></a>,
	<%=member.getEmail() %>,
	<%=member.getCreateDate() %>
	<a href="delete?no=<%=member.getNo()%>">삭제</a><br>
	<%} %>
	<jsp:include page="/Tail.jsp"/>
</body>
</html>

 

MemberDeleteServlet.java

package spms.servlets;

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

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;

/**
 * Servlet implementation class MemberDeleteServlet
 */
@WebServlet("/member/delete")
public class MemberDeleteServlet extends HttpServlet {
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		Connection conn = null;
		Statement stmt = null;
		
		String sqlDelete = "DELETE FROM MEMBERS WHERE MNO=" + request.getParameter("no");
		
		try {
			ServletContext sc = this.getServletContext();
			
			conn = (Connection)sc.getAttribute("conn");
			stmt = conn.createStatement();
			
			stmt.executeLargeUpdate(sqlDelete);
			
			response.sendRedirect("list");
		} catch(Exception e) {
			e.printStackTrace();
			request.setAttribute("error", e);
			RequestDispatcher rd = request.getRequestDispatcher("/error.jsp");
			rd.forward(request, response);
		} finally {
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

Header.jsp

<%@ page import="spms.vo.Member" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean id="Member" 
			 scope="session" 
			 class="spms.vo.Member">
</jsp:useBean>    
 
<%
	//HttpSession 데이터 보관소에 저장된 member 객체 꺼내서 사용
	//Member member = (Member)session.getAttribute("Member");
%>
<div style="background-color:#00008b; color:#ffffff; height:20px; padding:5px">
SPMS(Simple Project Management System)
<span style="float:right;">
	<%=Member.getName() %>
	<a style="color:white;" href="<%=request.getContextPath() %>/auth/logout">로그아웃</a>
</span>
</div>

 

실행 화면

- 일지매 회원이 삭제됨

 

 

반응형

댓글