82일차 Session/Cookie

쿠우·2022년 7월 22일
0

세션 관리 ( session tracking )

세션(Session) : 추상적인 연결, 계속 유지되는 연결

HTTP protocol (통신규약) :

    1. 연결이 유지 되지 않는다.
    1. 연결생성 > 요청전송 > 응답 수신 > 연결종료
    1. Connectionless (비연결성): HTTP는 기본이 연결을 유지하지 않는 모델
      Stateless(무상태):서버가 클라이언트의 세션 상태 및 세션 정보를 저장하지 않는 네트워크 프로토콜
      ==> 물리적인 세션(지속적 연결)의 생성은 불가능!
      ==> 추상적인 연결로 세션을 생성/ 관리 (방법 2가지):

(1) HttpSession 객체를 이용하는 세션처리 방법

-이 방법을 많이 사용함 왜? 쿠키차단기능때문에

-WAS server에 Session Scope영역에 저장된다.

Session
클라이언트와의 추상적인 지속적인 연결은 Session scope 공유영역으로 구현한다.

대부분의 WAS는 30분을 기본으로 미사용 Session scope를 파괴한다.
1) 유지시간의 변경
-> 이것은 web.xml 에서 조절가능하다.(서버프로그램의 데이터 사용량을 조절)
-> session.setMaxInactiveInterval(Millisecond) 메소드를 사용

2) 즉시 파괴
-> session.invalidate() 메소드사용

HttpSession 객체 이용 장바구니를 만드는 예제

알아본 점
-(0)HTTPSession 객체를 이용 .getSession()를 통한 반환값 이용한다.
-(1)sess.invalidate()메소드로 즉시삭제
-(2)requireNonNull Null일 때 예외가 발생하도록
-(3)request.getSession(false)은 Session 없을경우 생성하지 않고 null을 반환

▼ 장바구니 저장부분


@WebServlet("/CartSave")
public class CartSaveServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		log.trace("service invoked");
		
//		-------------------------------
//		Step.1 장바구니에 저장할 상품항목을 전송파라미터로 획득 
//		-------------------------------
		
		request.setCharacterEncoding("utf8");

		String product = request.getParameter("product");
		log.info("\t + product: {}", product);

//		-----------------------------------
//		Step.2 장바구니 생성 및 수신된 상품을 장바구니에 추가 
//		------------------------------------
		
		HttpSession sess = request.getSession();
		
		@SuppressWarnings("unchecked")
		List<String> list = (List<String>) sess.getAttribute("basket");
		
		if(list == null) {   // Session 장바구니가 없으면 
			list = new ArrayList<>();   // 장바구니를 만들고 
			sess.setAttribute("basket", list); // 그 안에 등록한다.
		}// if -else
		
		list.add(product);
		log.info("\t + list: {}", list);
		
//		=========================
//		응답화면 생성 및 전송
//		=========================		
	
		response.setContentType("text/html; charset=utf8");
		
		@Cleanup
		PrintWriter out = response.getWriter();
		
		out.println("<h1>장바구니 담기 성공</h1>");
		out.println("<a href='/CartBasket'>장바구니 보기</a>");
		
		out.flush();
		
	}// service
}// end class

▼ 보여주는 부분

	@SuppressWarnings("unchecked")
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		log.trace("service invoked");

		List<String> list = null;
		
		try {
			HttpSession sess = request.getSession(false); // 현재 브라우저의 대한 세션이 있으면 주고 없으면 만들지마라 
			log.info("\t+ sess : {} ", sess);
			
			Objects.requireNonNull(sess);
			
			list = (List<String>) sess.getAttribute("basket");
			
			Objects.requireNonNull(list);
			
			list.forEach(log::info);
			
		}catch(Exception e) {
			throw new ServletException(e);
		}// try- catch
			
//		=============
		
		response.setContentType("text/html; charset=utf8");
		
		@Cleanup
		PrintWriter out = response.getWriter();
		
		out.println("<h1>장바구니 내용</h1>");
		out.println("<ol>");

		list.forEach(s ->{
			out.println("\t<li>"+s+"</li>");
		}); // foreach
		
		out.println("</ol>");
		
		out.println("<a href='/CartDelete'>장바구니 비우기 </a>");
		
		out.flush();
		
		
	}// service
}// end class

▼ 장바구니 비우는 부분


@WebServlet("/CartDelete")
public class CartDeleteServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		log.trace("service invoked");
		
		// 장바구니 비우기 : 현재 브라우저의 세션아이디(이름)로 
		//식별되는 Session Scope 공유영역 파괴! + 세션아이디 무효화
		HttpSession sess = request.getSession(false);
		
		
		try {
			Objects.requireNonNull(sess);
			
			sess.invalidate(); // Session ID 무효화  + Session Scope 영역 파괴!
			
//			===============
//			마지막 응답 페이지는 요청포워딩(Request Forwarding)을 통해, 
//			아직 배우지는 않았지만, JSP에서 생성하도록 함 
//			===============
			
			RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/views/cartdelete.jsp");
			

		} catch (Exception e) {
			throw new ServletException(e);
		}
		
		
//		=========================
//		응답화면 생성 및 전송
//		=========================		
	
		response.setContentType("text/html; charset=utf8");
		
		@Cleanup
		PrintWriter out = response.getWriter();
		
		out.println("<h1>장바구니 비우기성공</h1>");
		
		out.flush();
		
	}// service
}// end class

(2) Cookie객체를 이용하는 쿠키처리 방법

-서버가 클라이언트한테 주는 작은 데이터를 의미 브라우저가 관리하는 쿠키파일에 저장하는 형식

-쿠키란 백엔드 서버에서 최초요청을 받았을 때 웹브라우저에 주는 쿠키가 있다. 이름은 JSESIONID , 값은 무작위 문자열로 받는다. 이 값을 세션 ID라고 부른다.

-최초요청의 받은 브라우저와 서버간의 명칭과 약속

*웹브라우저는, 특정 웹사이트 주소로, "최초요청"을 보낸결과
자기의 이름으로 "세션아이디"를 쿠키로 받게 되고, 이를
쿠키파일로 저장(웹사이트 주소마다 다른파일로 저장)

   - 이후, 두번째 이상 요청부터는, 동일한 브라우저라면 요청을
      보낼 때마다, 반드시, 해당 웹사이트 주소로 보관된 쿠키파
      이 존재한다면, 이 쿠키파일을 읽어서, 다시 서버로 전송
      (요청문서의 헤더(Cookie)에 저장되어 전송됨)

   - 어느때까지 요청헤더에 쿠키값을 저장해서 전송하는가!?
     이 웹브라우저가 죽을 때까지.... 브라우저가 죽으면 왜 파괴되는지 이해하라
     브라우저가 파괴되고 다시 시작하면 다른 아이디를 부여받는다.
     (실험결과: 브라우저에서 페이지 창을 여러개 띄웠는데 다 똑같은 ID를 갖는다.)

-알아본 점
(1)Cookie 객체의 생성자를 이용한다. / new Cookie("이름","값") -> 맵형태로 생성
(2)getCookies() 메소드로 쿠키 객체를 가져온다.
(3)Cookie 객체에는 .getName()과 .getValue를 사용해서 이름과 값을 얻음
(4)setMaxAge(seconds) 메소드로 만료기간을 조정해서 삭제한다.

▼장바구니 저장부분


@WebServlet("/CartSaveCookie")
public class CartSaveCookieServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		log.trace("service invoked");
		
//		-------------------------------
//		Step.1 화면에서 전송한, 장바구니에 저장할 품목 (전송파라미터) 획득
//		-------------------------------
		
		request.setCharacterEncoding("utf8");

		String product = request.getParameter("product");
		log.info("\t + product: {}", product);

//		-----------------------------------
//		Step.2 요청메시지(Request Message) 의 헤더(이름: Cookie)에 포함되어 있는, 모든 쿠키 획득
//		------------------------------------
		Cookie[] cookies = request.getCookies(); // 쿠키타입의 객체를 원소로 하는 객체배열 반환
		
//		-----------------------------------
//		Step.3 우리가 직접 새로운 쿠키를 생성하자!!
//		------------------------------------
		Cookie cookie = null; 
		
		if(cookies == null || cookies.length == 0) { // 위 Step.2에서 얻는 쿠키배열이 무효하다면
			cookie = new Cookie("product",product);						// 새로운 쿠키객체 생성
		} else {		// 위 Step.2에서 얻은 쿠키배열이 유효하다면...
			cookie = new Cookie("product"+(cookies.length +1), product); // 새로운 쿠키객체 생성
		}// if-else
		
//		-----------------------------------
//		Step.4 우리가 생성한 쿠키의 만료기간 설정
//		------------------------------------		
		cookie.setMaxAge(60*60); // in seconds, 1시간동안 유지하라! (어디? 브라우저에서)
		
//		-----------------------------------
//		Step.5 응답메시지의 헤더에, 우리가 위 step.3 에서 생성한 쿠키객체를 저장 
//		------------------------------------	
		response.addCookie(cookie);
		
//		=========================
//		응답화면 생성 및 전송
//		=========================		
	
		response.setContentType("text/html; charset=utf8");
		
		@Cleanup
		PrintWriter out = response.getWriter();
		
		out.println("<h1>Product 추가</h1>");
		out.println("<a href='/CartBasketCookie'>장바구니 보기</a>");
		
		out.flush();
		
	}// service
}// end class

▼장바구니 목록 보여주는 부분


@WebServlet("/CartBasketCookie")
public class CartBasketCookieServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@SuppressWarnings("unchecked")
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		log.trace("service invoked");

//		Step.1 
//		나의 모든 장바구니 항목을 담고있는 쿠키목록을 웹브라우저가
//		request message의 헤더(이름: Cookie)에 담아서 보내오게 되어있다. (웹브라우저 기본동작)
		
		Cookie[] basket = request.getCookies();
		log.info("* basket : {} ", Arrays.toString(basket));
		
//		Step.2 -----------------------
//		응답문서 생성 using Step.1에서 얻은 장바구니 목록을 이용 
		
		response.setContentType("text/html; charset=utf8");
		
		@Cleanup
		PrintWriter out = response.getWriter();
		
		
		if(basket ==null) {
			out.println("장바구니에 아무것도 없다이");
		} else {
			for(Cookie cookie : basket) {
				String name = cookie.getName();
				String value = cookie.getValue();
				
				out.println("<h1>"+name+" : " + value+"</h1>");
			}//for
		}// if - else
		
		out.println("<a href = 'product.html'>상품선택 페이지</a>");
		out.println("<a href = '/CartDeleteCookie'>장바구니 비우기</a>");
		
		out.flush();

	}// service
}// end class

▼장바구니 목록 삭제부분

@WebServlet("/CartDeleteCookie")
public class CartDeleteCookieServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	// 클라이언트 브라우저에 쿠키파일로 저장되어있는 모든 장바구니 데이터를 삭제 
	// How? 각 쿠키의 만료 기간을 조작(중요!) 
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		log.trace("service invoked");
		
//		============================================
//		Step.1 - 웹 브라우저가 보낸 request 메시지의 헤더에 있는 모든 쿠키를 배열로 획득 
//		============================================
		Cookie[] basket = request.getCookies();
		
		
//		============================================
//		Step.2 - 각 쿠키의 만료기간을 1초 (0초는 허용안함)으로 바꾸어서 , 바로 만료하게 만든다.
//		============================================
		if(basket !=null) {		//장바구니가 있다면..
			for(Cookie cookie:basket) {
				cookie.setMaxAge(1);	// in seconds, 만료기간 = 1초로 변경 (즉, 바로 삭제시켜라! 란 의미가된다.)
				
				//1초의 만료기간으로 변경된 쿠킫글을 다시 브라우저로 보내면 
				// 웹브라우저는 이 사이트 주소에 대해 파일을 보관중이던, 모든 쿠키의 만료기간이 1초로 단축되었기때문에 
				// 1초후에 모든 쿠키(=작은데이터, 이름 = 값 형태) 파괴시켜버림 
				response.addCookie(cookie); 	// 시간만료가 설정된 쿠키를 브라우저로 전송
			}//for
			
			
		}//if
		
//		=========================
//		응답화면 생성 및 전송
//		=========================		
	
		response.setContentType("text/html; charset=utf8");
		
		@Cleanup
		PrintWriter out = response.getWriter();
		
		out.println("<h1>장바구니 비우기성공</h1>");
		
		out.flush();
		
	}// service
}// end class

결과 브라우저 쪽에 쿠키 객체를 저장

쿠키차단 기능을 고려해가면서 브라우저와 서버의 메모리를 적절히 분할해가면서 사용하면 좋을듯 싶다.

파일 업로드 및 다운로드 기능

Servlet 3.0부터 어노테이션 지원으로 단순하게 업로드 다운로드는 어렵지는 않다.
단 원본파일이 아닌 날짜 별로 폴더안에 구분하고 UUID기반으로 저장해야함

(HTML의 양식태그에서 post방식으로 넘어오는 데이터에 part별로 구분되는 것을 알아야함)

profile
일단 흐자

0개의 댓글