[서블릿] 서블릿 쿠키와 세션 1-2

hoonak·2023년 6월 22일
0

서블릿

목록 보기
10/16

웹 페이지 연결 기능
보통 웹 프로그램에서 사용되는 정보는 서블릿의 비즈니스 로직 처리 기능을 이용해 데이터베이스에서 가져옴. 그러나 동시 사용자 수가 많아지면 데이터베이스 연동 속도도 영향을 받게 되므로 정보의 종류에 따라 어떤 정보들을 클라이언트 PC나 서버의 메모리에 저장해두고 사용하면 좀 더 프로그램을 빠르게 실행시킬 수 있음.

세션 트래킹
온라인 쇼핑몰을 이용하다 보면 메인 페이지에서 미리 로그인한 후 다른 웹 페이지에서 상품에 관한 댓글을 달거나 게시판에 상품명을 달곤 함. 글쓰기창에서는 따로 로그인하지 않아도 됨. 그러나 메인 페이지에서 미리 로그인하지 않고 새 글을 작성하려면 '로그인 후 이용하라는' 메시지가 나타남. 그러면 사용자는 로그인한 후 글쓰기창으로 이동하게 됨. 쇼핑몰을 이용하는 일반 사용자들은 로그인 상태를 각각의 웹 페이지들이 자동적으로 알고 있을 것이라고 생각함. 하지만 실제 HTTP 프로토콜 방식으로 통신하는 웹 페이지들은 서로 어떤 정보도 공유하지 않음. 사용자 입장에서 웹 페이지 사이의 상태나 정보를 공유하려면 프로그래머가 세션 트래킹 이라는 웹 페이지 연결 기능을 구현해야 함.

HTTP 프로토콜은 서버-클라이언트 통신 시 stateless 방식으로 통신을 함. 즉, 브라우저에서 새 웹페이지를 열면 기존의 웹 페이지나 서블릿에 관한 어떤 연결 정보도 새 웹 페이지에서는 알 수 없음.

정리하면 HTTP 프로토콜은 각 웹 페이지의 상태나 정보를 다른 페이지들과 공유하지 않는 stateless 방식으로 통신을 함. 따라서 웹 페이지나 서블릿끼리 상태나 정보를 공유하려면 웹페이지 연결 기능, 즉 세션 트래킹을 이용해야 함.

웹 페이지를 연동하는 방법

  • hidden 태그 :
    HTML의 hidden 태그를 이용해 웹 페이지들 사이의 정보를 공유함.

  • url Rewriting :
    get 방식으로 url 뒤에 정보를 붙여서 다른 페이지로 전송함.

  • 쿠키 :
    클라이언트 PC의 Cookie 파일에 정보를 저장한 후 웹 페이지들이 공유함.

  • 세션 :
    서버 메모리에 정보를 저장한 후 웹 페이지들이 공유함.

예 1) hidden 태그를 이용한 세션 트래킹
hidden 태그는 브라우저에 표시되지 않지만 미리 저장된 정보를 서블릿으로 전송할 수 있음.

로그인창에서 id와 비밀번호를 입력하면 미리 hidden 태그에 저장된 주소, 이메일, 휴대폰 번호를 서블릿으로 전송함.

login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>	
	<form name = "frmLogin" method = "post" action = "login" encType = "UTF-8">
	아이디 : <input type = "text" name = "user_id"><br>
	비밀번호 : <input type = "password"	 name = "user_pw"><br>
	<input type = "submit" value = "로그인">
	<!-- <hidden> 태그의 value 속성에 주소, 이메일, 전화번호를 지정한 후 서블릿으로 전송. -->
	<input type = "hidden" name = "user_address" value = "서울시 성북구" /> 
	<input type = "hidden" name = "user_email" value = "test@naver.com" />
	<input type = "hidden" name = "user_hp" value = "010-111-2222" />	
	</form>
</body>
</html>

getParameter() 메서드를 이용해 전송된 회원 정보를 가져온 후 브라우저로 다시 출력함.

LoginServlet.java

package sec01.ex01;

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

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("/login")
public class LoginServlet extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		String user_id = request.getParameter("user_id");
		String user_pw = request.getParameter("user_pw");
		//<hidden> 태그로 전송된 값을 getParameter() 메서드를 이용해 가져옴
		String user_address = request.getParameter("user_address"); 
		String user_email = request.getParameter("user_email");
		String user_hp = request.getParameter("user_hp");
		
		String data = "안녕하세요 <br> 로그인하셨습니다.<br><br>";
		data += "<html><body>";
		data += "아이디 : " + user_id;
		data += "<br>";
		data += "패스워드 :" + user_pw;
		data += "<br>";
		data += "주소" + user_address;
		data += "<br>";
		data += "이메일" + user_email;
		data += "<br>";
		data += "핸드폰" + user_hp;
		data += "</body></html>";
		out.print(data);
	}
	
	public void destory() {
		System.out.println("destory 메서드 호출");
	}

}

예 2) URL Rewriting을 이용한 세션 트래킹
url Rewriting을 이용해 로그인 창에서 입력 받은 id 와 비밀번호를 다른 서블릿으로 전송하여 로그인 상태를 확인.

로그인창에서 입력 받은 id와 비밀번호를 a 태그의 두 번째 서블릿으로 보내기를 클릭하면 로그인창에서 입력한 id와 비밀번호 그리고 다른 정보들을 get 방식을 이용해 두 번째 서블릿으로 전송함.

LoginServlet.java

package sec01.ex01;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

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("/login")
public class LoginServlet extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		String user_id = request.getParameter("user_id");
		String user_pw = request.getParameter("user_pw");
		//<hidden> 태그로 전송된 값을 getParameter() 메서드를 이용해 가져옴
		String user_address = request.getParameter("user_address"); 
		String user_email = request.getParameter("user_email");
		String user_hp = request.getParameter("user_hp");
		
		String data = "안녕하세요 <br> 로그인하셨습니다.<br><br>";
		data += "<html><body>";
		data += "아이디 : " + user_id;
		data += "<br>";
		data += "패스워드 :" + user_pw;
		data += "<br>";
		data += "주소" + user_address;
		data += "<br>";
		data += "이메일" + user_email;
		data += "<br>";
		data += "핸드폰" + user_hp;
		data += "</body></html>";
		out.print(data);
		
		user_address = URLEncoder.encode(user_address, "utf-8"); // get 방식으로 한글을 전송하기 위해 인코딩함.
		// a 태그를 이용해서 링크 클릭 시 서블릿 /second로 다시 로그인 정보를 전송함.
		out.print("<a href = '/pro09/second?user_id="+user_id+"&user_pw="+user_pw+"&user_address="+user_address+"'>두 번째 서블릿으로 보내기</a>");
	}
	
	public void destory() {
		System.out.println("destory 메서드 호출");
	}

}

첫 번째 서블릿에서 전송한 데이터 중 id와 비밀번호를 가져왔으며 이미 첫 번째 서블릿에서 로그인한 것이므로 로그인 상태를 유지하도록 해줌.

SecondServlet.java

package sec01.ex01;

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

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("/second")
public class second extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		
		// 첫 번째 서블릿에서 전송한 로그인 정보를 가져옴.
		String user_id = request.getParameter("user_id"); 
		String user_pw = request.getParameter("user_pw");
		String user_address = request.getParameter("user_address");
		
		out.println("<html><body>");
		if(user_id != null && user_id.length() != 0) {
			// 첫 번째 서블릿의 id 정보를 이용해 로그인 상태를 유지.
			out.println("이미 로그인 상태입니다<br><br>");
			out.println("첫 번째 서블릿에서 넘겨준 아이디 :" + user_id + "<br>"); 
			out.println("첫 번째 서블릿에서 넘겨준 비밀번호" + user_pw + "<br>");
			out.println("첫 번째 서블릿에서 넘겨준 주소" + user_address + "<br>");
			out.println("</body></html>");			
		}else {
			// 로그인창을 거치지 않고 바로 요청한 경우에는 로그인창으로 다시 이동하도록 안내함.
			out.println("로그인 하지 않았습니다 <br><br>"); 
			out.println("다시 로그인 하세요 <br>");
			out.println("<a = href '/pro09/login.html'> 로그인창으로 이동하기 </a>");
		}
	}


}

지금까지 hidden 태그와 get 방식으로 웹 페이지들을 연동하는 방법을 알아봄. 그런데 이 방법은 여러 가지 단점이 있음. 일단 웹 페이지가 많아지면 일일이 로그인 상태를 확인 하기 위해 로그인 정보를 다른 웹 페이지로 전송해야 한다는 것.

그리고 id와 비밀번호를 get 방식으로 전송하므로 브라우저에 노출되어 보안상으로도 좋지 않음. 또한 전송할 수 있는 데이터 용량에도 한계가 있음. 따라서 이 방식은 웹 페이지 사이에 간단한 정보 정도를 공유할 때만 사용하는 것이 좋음.

쿠키를 이용한 웹 페이지 연동 기능

쿠키

웹 페이지들 사이의 공유 정보를 클라이언트 PC에 저장해 놓고 필요할 때 여러 웹 페이지들이 공유해서 사용할 수 있도록 매개 역할을 하는 방법임.

쿠키의 특징

  • 정보가 클라이언트 PC에 저장됨.

  • 저장 정보 용량에 제한이 있음(파일 용량은 4kb).

  • 보안이 취약함.

  • 클라이언트 브라우저에서 사용 유무를 설정할 수 있음.

  • 도메인당 쿠키가 만들어 짐(웹 사이트당 하나의 쿠키가 만들어짐).

    쿠키는 클라이언트PC에 정보를 저장해서 사용하므로 보안에 취약함. 따라서 쿠키를 이용한 방법은 주로 보안과 무관한 경우에 한해 사용함. 예를 들어 우리가 웹 페이지를 방문했을 때 어떤 팝업창이 나타나면 '오늘은 더 이상 보지 않기'를 체크하는데, 이처럼 팝업창이 나타나지 않게 하는 경우 등에 사용함.

쿠키의 종류

  1. Persistence 쿠키
  • 생성위치 : 파일로 생성.
  • 종료시기 : 쿠키를 삭제하거나 쿠키 설정 값이 종료된 경우.
  • 최초 접속 시 전송 여부 : 최초 접속 시 서버로 전송.
  • 용도 : 로그인 유무 또는 팝업창을 제한할 때.
  1. Session 쿠키
  • 생성위치 : 브라우저 메모리에 생성.
  • 종료시기 : 브라우저를 종료할 경우.
  • 최초 접속 시 전송 여부 : 최초 접속 시 서버로 전송되지 않음.
  • 용도 : 사이트 접속 시 Session 인증 정보를 유지할때.

Persistence 쿠키는 클라이언트에 파일로 정보를 저장하는 기능을 함. 파일로 생성된 쿠키는 사용자가 만료 시간을 지정할 수 있는 반면에 Session 쿠키는 브라우저가 사용하는 메모리에 생성되는 쿠키임. 브라우저가 종료되면 메모리의 Session 쿠키도 자종으로 소멸됨.

쿠키 생성 과정
1. 브라우저로 사이트에 접속함.
2. 서버는 정보를 저장한 쿠키를 생성함.
3. 생성된 쿠키를 브라우저로 전송함.
4. 브라우저는 서버로부터 받은 쿠키 정보를 쿠키 파일에 저장함.
5. 브라우저가 다시 접속해 서버가 브라우저에게 쿠키 전송을 요청하면 브라우저는 쿠키 정보를 서버에 넘겨줌.
6. 서버는 쿠키 정보를 이용해 작업을 함.

쿠키 API
쿠키는 Cookie 클래스 객체를 생성하여 정보를 저장한 후 서버에서 클라이언트로 전송해 파일로 저장됨.

  • javax.servlet.http.Cookie를 이용함.
  • HttpServletResponse의 addCookie() 메서드를 이용해 클라이언트 브라우저에 쿠키를 전송한 후 저장함.
  • HttpServletRequest의 getCookie() 메서드를 이용해 쿠키를 서버로 가져옴.

쿠키 클래스의 여러 가지 메서드

  • getComment() : 쿠키에 대한 설명을 가져옴.

  • getDomain() : 쿠키의 유효한 도메인 정보를 가져옴.

  • getMaxAge() : 쿠키 유효 시간을 가져옴.

  • getName() : 쿠키 이름을 가져옴.

  • getPath() : 쿠키의 디렉터리 정보를 가져옴.

  • getValue() : 쿠키의 설정 값을 가져옴.

  • setComment(String) : 쿠키에 대한 설명을 설정함.

  • setDomain(String) : 쿠키의 유효한 도메인을 설정함.

  • setMaxAge(int) : 쿠키 유효 시간을 설정함.

  • setValue(String) : 쿠키 값을 설정함.

  • setPath(String) : 쿠키의 디렉터리 정보를 설정함.

setMaxAge() 메서드 인자 값의 종류를 지정해서 파일에 저장하는 Persistence 쿠키를 만들거나 메모리에만 저장하는 Session 쿠키를 만들 수 있음.
인자값으로 음수나 setMaxAge() 메서드를 사용하지 않고 쿠키를 만들면 Session 쿠키로 저장됨. 인자 값으로 양수를 지정하면 Persistence 쿠키로 저장됨.

예 1) 서블릿에서 쿠키 사용

Cookie 객체를 생성한 후 쿠키 이름을 cookieTest로 값을 저장함. 그리고 setMaxAge() 메서드에 쿠키 유효 시간을 24시간으로 설정함. 그런 다음 response의 addCookie()메서드를 이용해 생성괸 쿠키를 브라우저로 전송함.

SetCookieValue.java

package sec02.ex01;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Date;

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

//@WebServlet("/set")
public class SetCookieValue extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		Date d = new Date();
		//Cookie 객체를 생성한 후 cookieTest 이름으로 한글 정보를 인코딩해서 쿠키에 저장함.
		Cookie c = new Cookie("cookieTest", URLEncoder.encode("JSP프로그래밍입니다.", "utf-8"));
				c.setMaxAge(24 * 60 * 60); // 유효기간을 설정
				response.addCookie(c); // 생성된 쿠키를 브라우저로 전송함.
				out.println("현재시간 : " + d);
				out.println("문자열을 cookie에 저장함");
	}
}

두 번째 서블릿 요청 시에는 request의 getCookie() 메서드를 호출해 브라우저로부터 쿠키를 전달받음. 그리고 전달된 쿠키에서 저장할 때 사용한 이름인 cookieTest로 검색해 값을 가져옴.

GetCookieValue.java

package sec02.ex01;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;

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

//@WebServlet("/get")
public class GetCookieValue extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		// request의 getCookies() 메서드를 호출해 브라우저에게 쿠키 정보를 요청한 후 쿠키 정보를 배열로 가져 옴.
		Cookie[] allValues = request.getCookies();
		// 배열에서 저장할 때 사용한 쿠키 이름인 cookieTest로 검색해 쿠키 값을 가져 옴.
		for(int i = 0; i < allValues.length; i++) { 
			if(allValues[i].getName().equals("cookieTest")) {
				out.println("<h2>Cookie 값 가져오기 : " + URLDecoder.decode(allValues[i].getValue(), "utf-8"));
			}
		}
	}
}

예 2) 세션 쿠키 사용하기

쿠키를 파일에 저장하는 것이 아닌, 브라우저가 사용하는 메모리에 저장하는 Session쿠리를 만들어 보겠음.

Cookie의 setMaxAge() 메서드를 이용해 유효 시간을 -1로 설정하면 세션 쿠기가 생성됨.

SetCookieValue.java

package sec02.ex02;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Date;

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

//@WebServlet("/set")
public class SetCookieValue extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		Date d = new Date();
		//Cookie 객체를 생성한 후 cookieTest 이름으로 한글 정보를 인코딩해서 쿠키에 저장함.
		Cookie c = new Cookie("cookieTest", URLEncoder.encode("JSP프로그래밍입니다.", "utf-8"));				
			c.setMaxAge(-1); // 유효시간을 음수로 지정하여 Session쿠키를 만듦.
			response.addCookie(c); // 생성된 쿠키를 브라우저로 전송함.
			out.println("현재시간 : " + d);
			out.println("문자열을 cookie에 저장함");
	}
}

예 3) 쿠키 이용해 팝업창 제한하기
팝업창 제어는 서버에서 쿠키를 다루지 않고 자바스크립트를 이용해 쿠키에 직접 접근함.

웹 페이지가 브라우저에 로드될 때 pageLoad() 함수를 호출한 후 쿠키에 접근해 팝업창 관련 정보를 가져옴. getCookieValue() 함수를 호출하여 쿠키 이름 notShowPop의 값이 true가 아니면 팝업창을 나타내고, notShowProp의 값이 true면 팝업창을 나타내지 않음.

popupTest.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	
	//브라우저에 웹페이지가 로드될 때 pageLoad()함수를 호출하여 실행.
	window.onload = pageLoad; 
	function pageLoad(){
    	// notShowPop의 쿠키값을 getCookieValue()를 호출하여 얻음.
		notShowPop = getCookieValue(); 
		if(notShowPop != "true"){ // notShowPop의 값이 true가 아니면 팝업창을 나타냄. 
			window.open("popUP.html", "pop", "width = 400,height = 500,history = no, resizable = no, status = no, scollbars = yes, menubar = no");
		}
		
	}
	
	function getCookieValue(){
		var result = "false";
		if(document.cookie != ""){
			// document의 cookie 속성으로 쿠키 정보를 문자열로 가져온 후 세미콜론(;)으로 분리해 각각의 쿠키를 얻음.
			cookie = document.cookie.split(";"); 
			for(var i = 0; i < cookie.length; i++){
				element = cookie[i].split("=");
				value = element[0];
				// 정규식을 이용해 쿠키 이름 문자열의 공백(\s)을 제거함.
				value = value.replace(/^\s*/,''); 
				//쿠키 이름이 notShowPop이면 해당하는 쿠키값을 가져와 반환함.
				if(value == "notShowPop"){ 
					reuslt = elment[1];
				}
			}
		}
		return result;
	}
	//'쿠키삭제' 클릭시 호출함.notShowPop 쿠키 값을 false로 설정함.
	function deleteCookie(){ 
		document.cookie = "notShowPop = " + "false" + ";path=/; expires=-1";
		
	}
	
</script>

</head>
<body>

	<form>
		<input type = "button" value = "쿠키삭제" onclick = "deleteCookie()"> <!--  쿠키를 삭제함 -->
	</form>

</body>
</html>

popUp.html에서는 오늘 더이상 팝업창 띄우지 않기에 체크하면 자바스크립트 함수인 setPopUpStart() 함수를 호출해 notShowPop의 값을 true로 설정하여 재접속 시 팝업창을 나타내지 않도록 설정함.

popUp.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	function setPopUpStart(obj){
		if(obj.checked == true){
			var expireDate = new Date();
			var days = 1; // 쿠키 유효 시간을 하루로 설정함.
			expireDate.setDate(expireDate.getDate() + days); //// 쿠키 유효 시간을 하루로 설정함.
			// 오늘 더 이상 파업창 띄우지 않기에 체크하면 notShowPop 쿠기 값을 ture로 설정하여 재접속 시 파업창을 나타내지 않음.
			document.cookie = "notShowPop=" + "true" + ";path=/; expires=" + expireDate.toGMTString();
			window.close();
		}
	}
</script>
</head>
<body>
	알림 팜업창입니다.
	<br><br><br><br><br><br>
	<form>
		<input type = "checkbox" onClick = "setPopUpStart(this)"> 오늘 더 이상 파업창 띄우지 않기
	</form>
</body>
</html>
profile
Hello World!

0개의 댓글