[Servlet] 세션 트래킹

sang·2024년 2월 16일

HTTP 프로토콜 통신 방식

stateless 방식의 서버-클라이언트 통신
각 웹 페이지의 상태나 정보를 다른 페이지들과 공유하지 않음
새 웹 페이지에서는 기존의 웹 페이지나 서블릿에 관한 정보를 알 수 없음

데이터 분할 저장

동시 사용자 수가 많으면 데이터베이스 연동 속도 저하
일부 정보들을 클라이언트 PC나 서버 메모리에 저장하여 해결

세션 트래킹

웹 페이지 사이의 상태나 정보를 공유하는 웹 페이지 연결 기능

  • <hidden> 태그: HTML 태그를 이용한 정보 공유
  • URL Rewriting: GET 방식으로 전송
  • 쿠키: 클라이언트 PC 쿠키 파일에 정보 저장
  • 세션: 서버 메모리에 정보 저장


<hidden> 태그

브라우저 미표시
미리 저장된 정보를 서블릿으로 전송

pro09/WebContent/login.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>로그인창</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="로그인">
    <input type="reset" value="다시 입력">
    
    /* <hidden> */
    <input type="hidden" name="user_address" value="서울시 성북구" />
    <input type="hidden" name="user_email" value="test@gmail.com" />
    <input type="hidden" name="user_hp" value="010-111-2222" />
  </form>
</body>
</html>

pro09/src/sec01/ex01/LoginServlet.java

package sec01.ex01;
...

@WebServlet("/login")
public class LoginServlet extends HttpServlet{
  public void init() {
    System.out.println("init 메서드 호출");
  }

  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");
    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+="email : "+user_email;
    data+="<br>";
    data+="휴대전화 : "+user_hp;
    data+="</body></html>";
    out.print(data);
  }

  public void destroy(){
    System.out.println("destroy 메서드 호출");
  }
}


URL Rewriting

GET 방식으로 한글 전송 시 인코딩 필요

pro09/src/sec01/ex02/LoginServlet.java

package sec01.ex02;
...

@WebServlet("/login")
public class LoginServlet extends HttpServlet{
  public void init(){
    System.out.println("init 메서드 호출");
  }
  
  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");
    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+="email : " +user_email;
    data+="<br>";
    data+="휴대전화 : " +user_hp;
    data+="<br>";
    out.print(data);

    user_address=URLEncoder.encode(user_address,"utf-8"); //한글 인코딩
    out.print("<a href='/pro09/second?user_id="+user_id+"&user_pw="+user_pw+"&user_address="+user_address+"'>두 번째 서블릿으로 보내기</a>"); //데이터 전송
    data="</body></html>";
    out.print(data);
  }

  public void destroy() {
    System.out.println("destroy 메서드 호출");
  }
}

pro09/src/sec01/ex02/SecondServlet.java

package sec01.ex02;
...

@WebServlet("/second")
public class SecondServlet extends HttpServlet{
  public void init() {
    System.out.println("init 메서드 호출");
  }
  
  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) {
      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'>로그인창으로 이동하기 </>");
    }
  }
  
  public void destroy(){
    System.out.println("destroy 메서드 호출");
  }
}


쿠키

웹 페이지 사이 공유 정보를 클라이언트 PC에 저장하여 사용할 수 있도록 하는 매개역할
클라이언트 PC에 정보 저장
저장 정보 용량 제한 존재
보안 취약
클라이언트 브라우저에서 사용 유무 설정 가능
도메인(웹 사이트) 당 쿠키 생성

쿠키 실행 과정

  1. 브라우저로 사이트 접속
  2. 서버가 정보 저장 쿠키 생성
  3. 브라우저로 쿠키 전송
  4. 브라우저가 쿠키 정보를 쿠키 파일에 저장
  5. 브라우저 재접속 시 서버의 쿠키 요청
  6. 브라우저에서 서버로 쿠키 전송
  7. 서버가 쿠키 정보를 이용해 작업 처리

쿠키 API

javax.servlet.http.Cookie

  • HttpServletResponse addCookie(): 클라이언트 브라우저에 쿠키 전송 및 저장
  • HttpServletRequest getCookie(): 서버로 쿠키 가져오기
  1. Cookie 클래스 객체 생성
  2. 객체에 정보 저장
  3. 클라이언트로 객체 전송
  4. 파일로 저장

getName(): 쿠키 이름
getComment(): 쿠키 설명
getDomain(): 유효 도메인 정보
getMaxAge(): 유효 기간(s)
getValue(): 설정 값
getPath(): 디렉토리 정보

setComment(String)
setDomain(String)
setMaxAge(int) - 음수 또는 미사용 시 session 쿠키
setValue(String)
setPath(String)

쿠키 생성 상태 확인

디버그창(F12) 상단 메뉴 바 Application
-> 왼쪽 메뉴 중 Cookies
-> http://localhost:8090

persistence 쿠키

파일로 생성
저장 위치: C:\Users\사용자\AppData\Local\Google\Chrome\User Data\Default\Cache
쿠키 삭제 또는 설정값 종료 시 쿠키 종료
최초 접속 시 서버 전송
로그인 유무 또는 팝업창 제한에 사용

pro09/src/sec02/ex01/SetCookieValue.java

package sec02.ex01;
...

@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 c = new Cookie("cookieTest",URLEncoder.encode("persistence","utf-8")); //한글 정보 인코딩 쿠키 생성
    c.setMaxAge(24*60*60); //유효 기간 24시간 설정
    response.addCookie(c); //브라우저로 쿠키 전송
    
    out.println("현재시간 : "+d);
    out.println("문자열을 Cookie에 저장");
  }
}

pro09/src/sec02/ex01/GetCookieValue.java

package sec02.ex01;
...

@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();
    
    /* 쿠키 정보 요청 및 가져오기 */
    Cookie[] allValues=request.getCookies();
    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"));
      }
    }
  }
}

session 쿠키

브라우저 메모리에 생성
브라우저 종료 시 쿠키 종료
최초 접속 시 전송 없음
인증 정보 유지에 사용

pro09/src/sec02/ex01/SetCookieValue.java

package sec02.ex01;
...

@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 c = new Cookie("cookieTest",URLEncoder.encode("session 쿠키","utf-8")); //쿠키 생성
    c.setMaxAge(-1); //음수 처리 -> session 쿠키
    response.addCookie(c); //쿠키 전송
    
    out.println("현재 시간 : "+d);
    out.println("현재 시간을 Cookie로 저장합니다.");
  }
}

팝업창 제한

pro09/WebContent/popupTest.html

<html>
<head>
 <meta charset="UTF-8">
 <title> 자바스크립트에서 쿠키 사용 </title>
 <script type = "text/javascript">
  window.onload = pageLoad; //브라우저에서 웹 페이지 로드 시 pageLoad 함수 호출
  
  function pageLoad(){
    notShowPop = getCookieValue(); //쿠키 값 얻어오기
    /* 쿠키 값이 true인 경우, 팝업창 나타내기 */
    if(notShowPop!="true"){ 
     window.open("popUp.html","pop","width=400,height=500,history=no, resizable=no,status=no,scrollbars=yes,menubar=no");
    }
  }
  
  function getCookieValue(){
    var result="false";
    /* 쿠키 정보 가져와서 문자열 분리 
    (쿠키이름1 = 쿠키값1; ... 쿠키이름n = 쿠키값n;) */
    if(document.cookie != ""){
      cookie = document.cookie.split(";");
      for(var i=0; i<cookie.length;i++){
        element=cookie[i].split("=");
        value=element[0];
        value=value.replace(/^\s*/,''); //정규식: 공백 제거
        if(value=="notShowPop"){ result = element[1]; }
      }
    }
    return result;
  }

  function deleteCookie(){
    /* 쿠키 삭제 처리: "notShowPop=false; path=/; expires=-1" */
    document.cookie = "notShowPop=" + "false" + ";path=/; expires=-1" ;
  }
 </script>
</head>

<body>
  <form>
    <!-- 쿠키 삭제 시 팝업 제한 쿠키 정보가 삭제되어 다시 팝업창 등장 -->
    <input type=button value="쿠키삭제" onClick="deleteCookie()">
  </form>
</body>
</html>

pro09/WebContent/popUp.html

<html>
  <head>
  <meta charset="UTF-8">
  <script type="text/javascript">
   function setPopUpStart(obj){
      if(obj.checked==true){
        /* 쿠키 유효 시간 설정: 하루 */
        var expireDate = new Date(); var days = 1;
        expireDate.setDate(expireDate.getDate() + days);
        /* 팝업창 제한 선택 시 쿠키 값 설정 */
        document.cookie ="notShowPop=" +"true" + ";path=/; expires=" + expireDate.toGMTString();
        window.close();
      }
   }
  </script>
  </head>
  
  <body>
    알림 팝업창입니다.
    <br><br><br><br><br><br><br>
    <form>
      <input type=checkbox onClick="setPopUpStart(this)">오늘 더 이상 팝업창 띄우지 않기
    </form>
  </body>
</html/>


세션

웹 페이지 간 공유 정보를 서버에 저장해두고 매개해주는 방식
서버 메모리에 정보 저장
보안이 필요한 정보에 사용
브라우저(사용자) 당 한 개 세션 생성
세션 유효 시간 존재 (기본 30분)
브라우저 세션 연동 시 세션 쿠키 이용
서버 부하에 가세함

세션 유효시간

유효시간 경과 시 기존 세션 삭제
유효시간 경과 후 재요청 시 새 새션 생성
ex) 부동 시 세션 만료로 인한 자동 로그아웃

세션 실행 과정

  1. 브라우저로 사이트 접속
  2. 서버: 접속 브라우저에 대한 세션 객체 생성
  3. 서버 -> 클라이언트 브라우저: 세션 id 응답
  4. 브라우저: 세션 쿠키 jsessionId에 세션 id 저장
  5. 브라우저 재접속 시, 브라우저 -> 서버: 세션 쿠키에 저장된 세션 id 전달
  6. 서버: 해당 세션에 접근하여 작업 수행

세션 API

HttpSession 클래스 객체를 통해 사용 가능
생성 시 getSession() 메소드 사용

  • getSession(): getSession(true)와 동일
  • getSession(true): 기존 세션 객체 존재 시 반환, 없으면 새로 생성
  • getSession(false): 기존 세션 객체 존재 시 반환, 없으면 null

HttpSession 클래스 메소드

Object getAttribute(String name): name 속성 값 반환
Enumeration getAttributeNames(): 세션 속성 이름들 반환
long getCreationTime(): 1970.01.01.00:00:00 ~ 세션 생성 시간 반환
String getId(): 세션 할당 고유 식별자 반환
int getMaxInactiveInterval(): 세션 유지 시간 반환
void invalidate(): 세션 소멸
boolean isNew(): 최초/기존 생성 여부 판별
void removeAttribute(String name): name 속성 제거
void setAttribute(String name, Object value): name 속성 값으로 value 할당
void setMaxInactiveInterval(int interval): 세션 유지 시간(s) 설정

다른 브라우저에서 새 세션 생성

크롬 주소창에서 /sess 요청


서블릿에서 세션 생성

pro09/src/sec03/ex01/SessionTest.java

package sec03.ex01;
...

@WebServlet("/sess")
public class SessionTest extends HttpServlet{
  protected void doGet(HttpServletRequest request , HttpServletResponse response ) throws ServletException, IOException {
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    
    HttpSession session = request.getSession(); //세션 생성 또는 반환
    
    /* 세션 정보 출력 */
    out.println("세션 아이디: "+ session.getId()+"<br>");
    out.println("최초 세션 생성 시각: "+ new Date(session.getCreationTime())+"<br>");
    out.println("최근 세션 접근 시각 : "+ new Date(session.getLastAccessedTime())+"<br>");
    
    /* 세션 유효시간 설정 */
    out.println("기본 세션 유효 시간 : "+ session.getMaxInactiveInterval()+"<br>"); //재설정 전 유효시간
    session.setMaxInactiveInterval(5); //유효시간 재설정: 5초
    out.println("세션 유효 시간 : "+ session.getMaxInactiveInterval()+"<br>"); //재설정 후 유효시간
    
    /* 최초/기존 생성 여부 판별 */
    if(session.isNew()) {
      out.print("새 세션이 만들어졌습니다.");
    }
    
    /* 세션 강제 삭제 */
    //session.invalidate(); //주석 해제 시 세션 생성 직후 즉시 소멸, 재요청 시 항상 다른 세션 생성
  }
}

로그인 정보 바인딩

HttpSession 바인딩

context.xml

...
<!-- 톰캣 종료 후 메모리에서 자동 세션 삭제 -->
<Manager pathname=”” /> <!-- 주석 해제 -->
...

pro09/WebContent/login2.html

<!DOCTYPE html>
<html>
<head></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="로그인">
      <input type="reset" value="다시 입력">
  </form>
</body>
</html>

pro09/src/sec03/ex04/SessionTest4.java

package sec03.ex04;
...

@WebServlet("/login")
public class SessionTest4 extends HttpServlet {
  protected void doGet(HttpServletRequest request , HttpServletResponse response) throws ServletException, IOException {
    doHandle(request, response);
  }

  protected void doPost(HttpServletRequest request , HttpServletResponse response) throws ServletException, IOException {
    doHandle(request, response);
  }
  
  private void doHandle(HttpServletRequest request , HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("utf-8");
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    
    HttpSession session = request.getSession();
  
    String user_id = request.getParameter("user_id");
    String user_pw = request.getParameter("user_pw");
    
    if (session.isNew()){
      if(user_id != null){
        session.setAttribute("user_id", user_id);
        out.println("<a href='login'>로그인 상태 확인</a>");
      } else {
        out.print("<a href='login2.html'>다시 로그인 하세요!!</a>");
        session.invalidate();
      }
    }
    else {
      user_id = (String) session.getAttribute("user_id");
      if (user_id != null && user_id.length() != 0) {
        out.print("안녕하세요 " + user_id + "님!!!");
      } else {
        out.print("<a href='login2.html'>다시 로그인 하세요!!</a>");
        session.invalidate();
      }
    }
  }
}

encodeURL()

쿠키 기능 사용 불가 시 대체 가능

  • 참고:
    세션 동작 시 세션 쿠키 이용
    쿠키 기능 사용 불가 -> 세션 기능 사용 불가

실행 과정

  1. encodeURL(): 서버 -> 브라우저 응답
  2. URL Rewriting: 브라우저 -> 서버 jsessionId(세션쿠키) 전송

pro09/src/sec04/ex01/SessionTest5.java

package sec04.ex01;
...

@WebServlet("/login")
public class SessionTest5 extends HttpServlet{
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doHandle(request, response); }
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doHandle(request, response); }

	private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	request.setCharacterEncoding("utf-8");
        reponse.setContentType("text/html; charset=utf-8");
        PrintWriter out = response.getWriter();
        
        HttpSession session = request.getSession();
        
        String user_id = request.getParameter("user_id");
        String user_pw = request.getParameter("user_pw");
        
        /* 4가지 상황 */
        if(session.isNew()) {      	
        	if(user_id != null) { /* 새로운 세션 + 아이디 O: 새로 로그인을 시도하는 상황 */
        		// 세션에 아이디 저장 + 로그인된 상태로 현재 페이지 다시 이동
                session.setAttribute("user_id", user_id);
            	String url = response.encodeURL("login");
            	out.println("<a href = "+url+">" + "login check" + "</a>");
        	} else { /* 새로운 새션 + 아이디 X: 로그인 중 아이디를 제출하지 않은 상황 */
            	// 로그인 페이지로 이동 + 세션 삭제
        		out.print("<a href = 'login2.html'> login again </a>");
            	session.invalidate();
        	}
        } else {
        	user_id = (String) session.getAttribute("user_id");
            /* 기존 세션 + 아이디 O: 이미 로그인이 되어있는 상태 */
            if(user_id != null && user_id.length() != 0) { out.print("login success: "+user_id); } // 따로 아이디 제출을 하지 않음
            /* 기존 세션 + 아이디 X: 로그인 세션이 만료된 상태 */
            else { out.print("<a href = 'login2.html'> login again </a>");  session.invalidate(); } // 로그인 페이지 이동 + 세션 삭제
        }
    }
}


*자바 웹을 다루는 기술

profile
CS 메모장

0개의 댓글