본문 바로가기
☕ Java 웹 프로그래밍/Servlet & JSP

[Servlet&JSP] Session 객체로 상태 값 저장하기 (+ Application 객체와의 차이점)

by 일단연 2023. 6. 1.

* 본 글은 [뉴렉처]의 Servlet&JSP 프로그래밍 강의를 듣고 정리한 글입니다.

 

2020 Servlet&JSP 프로그래밍

 

www.youtube.com

 

 Session 객체로 상태 값 저장하기 (+ Application 객체와의 차이점) 

Session 객체

  • Application 객체와 같이, 상태를 저장하거나 앞에서 다룬 결과를 잠깐 저장하기 위해 사용하는 객체
  • Application 객체와 사용법이 같음
  • Application 객체의 사용법
ServletContext application = request.getServletContext( );
...
int x = (Integer)application.getAttribute("value");
...
String operator = (String)application.getAttribute("op");
...
application.setAttribute("value", v);
application.setAttribute("op", op);
  • Session 객체의 사용법
HttpSession session = request.getSession( );
...
int x = (Integer)session.getAttribute("value");
...
String operator = (String)session.getAttribute("op");
	...
session.setAttribute("value", v);
session.setAttribute("op", op);

 

Application 객체와 Session 객체의 차이점

  • Application 객체
    • 서블릿이 애플리케이션 전역에서 사용할 수 있는 공간
  • Session 객체
    • 서블릿이 세션 범주 내에서 사용할 수 있는 공간
    • Session = 현재 접속한 사용자
  • 크롬은 여러 개의 창을 띄워도 어떤 창도 끊기지 않음 (언제 접속하더라도 모두 현재 접속한 사용자로 인식한다는 뜻)
    • 크롬은 하위 흐름을 갖고 있는 스레드로 여러 개의 창을 띄움
    • 스레드는 프로세스의 자원을 다같이 공유함
    • 웹서버에 요청하면 같은 프로세스를 요청한 것으로 인식되기 때문에 같은 사용자/Session으로 인식됨
    • 그러면 웹 서버는 현재 사용자(Session)를 어떻게 구분할까?

 

웹 서버가 현재 사용자(Session)를 구별하는 방법

  • 클라이언트는 브라우저를 이용해 서버에 요청
  • 서버에는 사용자의 요청을 수반한 프로그램을 처리
  • 그 프로그램에서 다른 서블릿에 공유하고 싶은 내용을 저장할 수 있는 공간에 Application과 Session이 존재
    • Application
      • 애플리케이션 전역에서 사용 가능한 공간
    • Session
      • 사용자마다 저장할 수 있는 공간
      • SID(Session ID)를 갖고 있는 사용자만 Session에 값을 저장할 수 있음
      • SID가 다르면, 사용자가 다르다고 봄
  • WAS(Web Application Server)가 세션 ID에 맞는 사용자 저장소를 구별하는 과정
    • 1) 클라이언트가 서버에 처음 요청을 전달할 땐 해당 브라우저는 SID가 없음
      • Application 이용 가능 / Session 이용 불가능
    • 2) 서버가 응답을 보낼 때 WAS가 클라이언트에 SID를 하나 발급해줌 > Session에 해당 아이디에 맞는 공간이 만들어짐
      • WAS는 같은 브라우저에게 항상 같은 SID를 발급함
    • 3) 클라이언트가 서버에 두 번째 요청을 전달할 땐 이전에 받은 SID를 갖고 있음
      • Application와 Session 모두 이용 가능
      • 브라우저는 항상 SID를 갖고 다님
      • 브라우저를 닫으면 SID가 사라짐 > Session 값도 사라짐
    • But, 브라우저가 달라지면 SID가 없으니까 첫 번째 요청에는 Session 이용 불가능 > 서버가 클라이언트에 SID 발급 > 두 번째 요청부터는 Session 이용 가능
  • SID 확인 방법: 브라우저마다 SID가 다름
  • 크롬

  • 엣지

  • SID를 복사해 요청하면 WAS는 같은 사용자로 인식
    • 이를 해결하기 위해 WAS들은 다양한 방법을 활용
      • 예: MS는 SID가 계속 바뀜

 

Session 메소드

  • void setAttribute(String name, Object value)
    • 지정된 이름으로 객체를 설정
  • Object getAttribute(String name)
    • 지정한 이름의 객체를 반환
  • void invalidate( )
    • Session 저장소를 비울 때 사용하는 메소드 (setAttribute( )메소드로 설정했던 것들을 지움)
    • 세션에서 사용되는 객체들을 바로 해제 (사용자 요청이 계속 올지 아닐지 알 수 없으니까)
  • void setMaxInactiveInterval(int interval)
    • 세션 타임아웃을 정수(초)로 설정
    • 세션 타임아웃: 이 시간 동안 사용자 요청이 안 오면 Session 저장소를 지우도록 제한시간을 주는 것
    • 기본 타임아웃은 30분이지만, 개별적으로 변경할 수도 있음
    • 1초 남은 상태에서 새로운 요청이 오면 타임아웃이 다시 30분으로 리셋되면서 다음 타임아웃이 진행됨
    • 타임아웃이 경과되는 순간 해당 타임아웃의 SID를 갖고 있는 사용자 요청이 오면 그 요청은 새로운 사용자 요청으로 인식됨
      • 유효하지 않은 SID가 되었기 때문에 해당 Session의 값들은 메모리에서 수거됨
  • boolean isNew( )
    • 세션이 새로 생성되었는지를 확인
  • long getCreationTime( )
    • 세션이 시작된 시간을 반환
    • 1970년 1월 1일을 시작으로 하는 밀리초
  • long getLastAccessedTime( )
    • 세션이 마지막으로 요청된 시간을 반환
    • 1970년 1월 1일을 시작으로 하는 밀리초
메소드 리턴타입 설명
setAttribute(String name, Object value) void 지정한 이름으로 객체를 설정
getAttribute(String name) Object 지정한 이름의 객체를 반환
invalidate( ) void • Session 저장소를 비울 때 사용하는 메소드 (setAttribute( )메소드로 설정했던 것들을 지움)
• 세션에서 사용되는 객체들을 바로 해제 (사용자 요청이 계속 올지 아닐지 알 수 없으니까)
setMaxInactiveInterval(int interval) void • 세션 타임아웃을 정수(초)로 설정
• 세션 타임아웃: 이 시간 동안 사용자 요청이 안 오면 Session 저장소를 지우도록 제한시간을 주는 것
• 기본 타임아웃은 30분이지만, 개별적으로 변경할 수도 있음
• 1초 남은 상태에서 새로운 요청이 오면 타임아웃이 다시 30분으로 리셋되면서 다음 타임아웃이 진행됨
• 타임아웃이 경과되는 순간 해당 타임아웃의 SID를 갖고 있는 사용자 요청이 오면 그 요청은 새로운 사용자 요청으로 인식됨
   ◦ 유효하지 않은 SID가 되었기 때문에 해당 Session의 값들은 메모리에서 수거됨
isNew( ) boolean 세션이 새로 생성되었는지를 확인
getCreationTime( ) long • 세션이 시작된 시간을 반환
• 1970년 1월 1일을 시작으로 하는 밀리초
getLastAccessedTime( ) long • 세션이 마지막으로 요청된 시간을 반환
• 1970년 1월 1일을 시작으로 하는 밀리초

 

Session 사용하기

  • Calc2.java
    • 값 v를 저장하기 위해 request의 getSession( )메소드를 사용하고, HttpSession형 변수에 저장
      • HttpSession session = request.getSession( );
    • 변수 session에 v과 op의 값을 저장하기 위해 setAttribute(name, object)메소드 사용
      • session.setAttribute("value", v); session.setAttribute("op", op);
package com.newlecture.web;

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

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;

@WebServlet("/calc2")
public class Calc2 extends HttpServlet {
  @Override
  protected void service(HttpServletRequest request
                        , HttpServletResponse response)
                        throws ServletException, IOException
  {
    ServletContext application = request.getServletContext();
    HttpSession session = request.getSession();
		
    //response의 인코딩 방식 지정
    response.setContentType("text/html; charset=UTF-8");
    response.setCharacterEncoding("UTF-8");
		
    PrintWriter out = response.getWriter();
		
    String v_ = request.getParameter("v");
    String op = request.getParameter("operator");
		
    //기본값 처리
    int v = 0;
    if(!v_.equals("")) {v = Integer.parseInt(v_);}
		
    //값을 계산
    if(op.equals("=")) {
      int x = (Integer)application.getAttribute("value");
      int y = v;
      String operator = (String)application.getAttribute("op");
			
      int result = 0;
			
      if(operator.equals("+")) {
        result = x + y;
      } else {
        result = x - y;
      }
      response.getWriter().printf("계산 결과는 %d\n", result);
    }
    //값을 저장
    else {
//    application.setAttribute("value", v);
//    application.setAttribute("op", op);
    
      session.setAttribute("value", v);
			session.setAttribute("op", op);
		}
  }
}
  • calc2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>계산기 웹 프로그램</title>
</head>
<body>
  <form action="calc2" method="post">
    <div>
      <p>계산할 값을 입력하세요.</p>
    </div>
    <div>
      <label>입력 : </label>
      <input type="text" name="v"/>
    </div>
    <div>
      <input type="submit" name="operator" value="+">
      <input type="submit" name="operator" value="-">
      <input type="submit" name="operator" value="=">
		</div>
  </form>
</body>
</html>