본문 바로가기

Languages/JSP

JSP - 세션관리



Staless 프로토콜


  • 세션에 대해 알아보기전에 우리는 HTTP의 프로토콜 특징에 대해 알아보고자 합니다.
  • HTTP 프로토콜을 기본적으로 클라이언트의 요청(request), 응답(response)로 구현되어 있습니다.
  • 이 말은, 서버에 요청을 하고 응답을 받으면 서버와의 통신이 끊기게 되고, 서버에는 클라이언트의 어떠한 정보도 유지하지 않는다는 뜻입니다.
  • 이것을 HTTP의 Staless특성인즉, 비연결형 프로토콜이라고 합니다.
    • 장점
      • 프로토콜을 직관적으로 이해하기 쉽고, 구현이 단순합니다.
      • 클라이언트의 요청에 대한 처리 결과를 응답으로 전송하고 나면 접속이 종료되기 때문에, 서버측 네트워크 자원의 효율 성이 증가합니다. 즉, 더 많은 클라이언트 요청을 처리 할 수 있습니다.
    • 단점
      • 각 클라이언트 요청마다 새로운 접속이 이루어지기 때문에 서버측의 네트워크 자원의 낭비가 적지만, 새로운 접속을 맺기 위해 발생하는 오버헤드 즉, 수행속도의 감소가 지속적으로 발생할 수 있습니다.
      • 또한, 동일한 클라이언트가 접속하더라도, 이전의 정보가 남아있지 않아서 클라이언트의 정보에 대한 비교가 불가능 합니다.

세션 (HTTP Session)


▶가상의 접속 상태를 유지하기 위한 메카니즘입니다.

  • HTTP세션이 종료되는 시점은, 클라이언트 세션 아이디가 무효화 되는 시점입니다. 이 시점은 로그 아웃 등을 할 때 종료된다고 보면 됩니다.
  • 웹에서 세션을 사용하고 있다면, 반드시 세션을 종료하는(로그아웃) 방법도 제공을 해주어야 합니다.
  • 일정 시간 동안 동일한 클라이언트로부터 요청이 발생하지 않는다면, 이 또한 세션이 종료되도록 할 수 있습니다. web.xml에 설정된 경우 <session-config> 의 <session-timeout>설정을 통해 시간 설정이 가능합니다.


    • 위의 설정대로 한다면, Session 은 30분후에 종료가 되겠다는 뜻이구요, 아파치 웹 서버를 따로 구성했을 경우에는 아파치 웹 서버의 WEB.XML을 수정해야 합니다.

쿠키


▶쿠키라는 것은 클라이언트의 상태 정보를 서버로 전송하기 위해 사용할 수 있는 방법 중의 하나로서 클라이언트에 저장되는 단순한 텍스트 입니다.

  • 쿠키는 브라우저가 종료되더라도 정보가 사라지지 않습니다.
  • 쿠키는 사용자가 컴퓨터를 켜든 끄든 하드디스크에 (상당기간) 저장되어 있습니다
  • 왜? PC에 저장하는 걸까요?
    • 그것은 HTTP 프로토콜이 'stateless' 프로토콜이기 때문입니다. 웹 브라우저가 웹 서버에 접속을 해서 어떤 문서나 파일을 요청하면 웹 서버는 요청 받은 내용을 보내준 다음 접속을 끊습니다.

      즉, 접속을 한 '상태(state)'가 지속되지 않고 요청된 것만 처리한 뒤 연결을 끊는 거죠. 그러므로 웹 서버는 일단 요청된 내용들을 클라이언트에 보내고 나면 그 뒤 사용자가 접속을 하고 있는지 어떤지 알 수가 없습니다.
    • 나아가, 예전에 접속했던 클라이언트가 또 접속을 한 것인지 아닌지 등은 더더욱 알 수 없습니다. 그런데 웹 사이트를 운용하는 측에서는 어떤 사용자가 다시 방문을 했는지 와 같은 정보가 절실히 필요했고 바로 이런 점을 해결하기 위해, 즉 stateless한 http의 특징을 커버하기 위해 등장한 아이디어가 쿠키(Cookie)입니다.
    • 쿠키의 아이디어는 간단합니다. 접속한 클라이언트의 하드디스크에 적당한 정보를 저장해 둠으로써 또 그 클라이언트가 접속한 경우 언제든지 하드디스크에 저장된 정보를 읽어 들여서 그 사용자를 인식할 수 있는 것입니다. '
    • 상태'에 관한 점검을 언제든지 할 수 있는 것이죠.
    • 쿠키에 저장되는 내용은 천차만별입니다. 간단하게는, 사용자가 어떤 페이지를 읽었고, 로그인 아이디가 뭐고, 이 메일 주소가 뭐고 등을 기록할 수도 있고, 사용자가 어떤 물품을 주문했는지, ip 주소가 뭐고, 어떤 사이트를 거쳐서 우리 사이트로 왔는지, 또는 서버에서 각 클라이언트를 식별할 특별한 정보를 기록하는 등, 거의 모든 형태의 정보를 저장할 수 있습니다.
    • 사용자 처지에서는 사실 기분 나쁠 수 있습니다. 나도 모르게 나의 행동이 하나하나 기록되어 '파일'로 저장되고 있고, 그 파일이 다른 곳도 아닌 '내' 컴퓨터에 나도 모르게 저장된다는 것은 별로 좋은 느낌은 아니죠.
    • 하지만, 쿠키 파일은 사용자가 컴퓨터를 끄든 켜든 하드디스크에 (상당 기간) 저장되어 있기 때문에, 언제든지 사용자가 다시 어떤 웹 사이트에 접속하면 쿠키에 저장해 놓은 정보를 읽어 들여서 여러 형태의 '맞춤화된' 서비스를 제공할 수 있습니다. 이를 테면, 로그인을 한 번만 하면 그 다음부터 안 해도 된다든지, 어떤 페이지를 "몇 번 보셨군요" 라고 알려준다든지 등이 가능합니다.
  • JSP에서 쿠키 설정하는 방법
    1. 헤더에 직접 지정하는 방법
      • HTTP 헤더를 이용한 쿠키 설정
      • Set-Cookie : name = value; expires = date; domain = serverDomain;
      • path = serverPath; secure(HTTPS)
    2. 쿠키를 추상화 시켜놓은 서블릿 API를 이용하는 방법
      • 이것은 보다 객체 지향적인 방법으로 클라이언트와 서버간의 쿠키 데이터 전송을 위해 Set-Cookie와 쿠키 헤더를 추상화한 javax.servlet.http.Cookie 클래스를 사용합니다.

JSP에서의 세션 관리


▶HttpSession과 세션 관리

  • HttpSession은 서블릿/JSP에서 세션을 유지하기 위해 필요한 일련의 작업을 단순화 혹은 추상화시켜 놓은 API라고 생각하면 될 것입니다.
  • 세션을 유지할 때는 다음의 방법을 사용합니다.
    1. 최초의 클라이언트에서 요청할 때 세션 유지를 위해 HttpSession 객체를 생성하고 고유한 세션 아이디를 생성합니다.
      • HttpSession session = request.getSession();
      • getSession()메소드는 create가 true일 경우 클라이언트 요청에 대해 기존에 생성된 객체가 존재할 때는 해당 객체를 리턴하고, 그렇지 않으면 새로운 객체를 생성하여 리턴합니다.
      • create가 false 인 경우에 요청에 대해 생성된 HttpSession객체가 존재할때 이를 리턴하고, 그렇지 않으면 null 을 리턴합니다.
      • 일반적으로 getSession()메소드는 getSession(true)과 동일하다고 보면 도비니다.
    2. HttpSession 객체 생성시 자동으로 생성된 세션 아이디를 이후의 클라이언트 요청부터 요청에 포함하여 전송합니다.
    3. 세션이 시작된 이후의 모든 요청이 들어올 때 마다 서버가 클라이언트에 부여한 세션 아이디를 통해 세션을 유지하도록 합니다.
  • [세션 테스트]

















차암 쉽쬬잉~~~~~~~~~♬

★만약, HttpSession을 사용하지 않고, page속성에서 session = true로 했을 경우에는 JSP 내장 Session객체를 사용함을 의미합니다. 이 때에HttpSession session 할 경우에는 동일한 session이름의 객체가 생성되므로 HttpSession으로 만든 session에 오류가 날 수있습니다. 이 때에는 HttpSession의 이름을 mySession 이나 뭐 기타 등등으로 바꾸면 됩니다.

★ 혹은, HttpSession을 쓰지 않고, JSP 내장 객체의 session을 사용하면 되겠는데, 이 때 jsp 내장객체의 session객체는 isNew()라는 메소드를 제공함으로써 세션의 존재 유무 혹은 세션이 현재 페이지에서 만들어졌는지 등을 알 수 있습니다.

HttpSessionBindingListener


jsp, 자바 빈( scope=application ) 하는 경우입니다.

굳이 db에 테이블을 생성하지 않아도 접속자 수를 실시간으로 구하실 수 있으실 겁니다.

=== SessionChecker.java ===============================

import java.io.*;
import java.util.*;
import javax.servlet.http.*;

public class SessionChecker{
public void setSession(HttpSession session){
// 리스너 객체를 생성해서 이것도 세션에 같이 담는다. 리스너 라는 이름으로...
session.setAttribute("listener", new CustomBindingListener());
}
}

//여기서구현했습니다..

class CustomBindingListener implements HttpSessionBindingListener {
public void valueBound(HttpSessionBindingEvent event) {
// 세션이 생겼을 할 내용
System.out.println("BOUND as " + event.getName() + " to " + event.getSession().getId());
}

public void valueUnbound(HttpSessionBindingEvent event) {
// 세션이 종료되었을때
System.out.println("UNBOUND as " + event.getName() + " to " + event.getSession().getId());
}
}


==== test.jsp =========================================


<%@ page contentType="text/html;charset=KS_C_5601-1987" %>
<jsp:useBean id="sc" class="SessionChecker" scope="application" />
<%
session.setMaxInactiveInterval(60); // 걍 결과가 빨리 보고싶어서여..60초
sc.setSession(session);
out.println("세션 등록");
%>

test 페이지를 연 후 60초 뒤에 unbound 어쩌구의 메세지를 보실 수 있을 겁니다.

[출처 : OKJSP > http://www.okjsp.pe.kr/seq/20524]

출처 : http://blog.naver.com/korekiss/20038228350

HttpSessionBindingListener 는 웹에서 동시 사용자의 수 또는 하나의 아이디로 동시접속을 제한 할때 유용한 인터페이스 이다. HttpSessionBindingListener 는 두개의 메소드를 지니는데 valueBound() 와 valueUnbound() 메소드 이다.

valueBound() 는 HttpSessionBindingListener 클래스의 인스턴스가 세션에 attribute로
등록될떄 호출된다 session.setAttribute(플래그, 값)
valueUnbound()는 session.removeAttribute(플래그); 사용시
또는 세션종료시 session.invalidate()호출된다.
다음은 이를 이용한 동시 사용자및 중복 로그인 방지 프로그램이다.
LoginManager.java

package itexpert.chap05;

import javax.servlet.http.HttpSession;

import javax.servlet.http.HttpSessionBindingListener;

import javax.servlet.http.HttpSessionBindingEvent;

import java.util.Hashtable;

import java.util.Enumeration;

public class LoginManager implements HttpSessionBindingListener

{

private static LoginManager loginManager = null

private static Hashtable loginUsers = new Hashtable();

private LoginManager(){

super();

}

public static synchronized LoginManager getInstance(){

if(loginManager == null){

loginManager = new LoginManager();

}

return loginManager

}

//아이디가 맞는지 체크

public boolean isValid(String userID, String userPW){

return true //자세한 로직은 미구현

}

//해당 세션에 이미 로그인 되있는지 체크

public boolean isLogin(String sessionID){ //세션 ID를 받습니다.

boolean isLogin = false

Enumeration e = loginUsers.keys();

String key = ""

while(e.hasMoreElements()){ //다음 데이터의 유무를 판단합니다.

key = (String)e.nextElement();//key변수에 대입.

if(sessionID.equals(key)){ //현재 세션 ID값과 로그인한 값을 비교합니다.

isLogin = true //해당되는 세션 아이디가 이미 등록되어 있다는 것을 의미.

}

}

return isLogin; //초기는 FALSE 이지요. WHILE문에서 걸러진다면 위에서 알아서 처리되겠습니다.

}

//중복 로그인 막기 위해 아이디 사용중인지 체크

public boolean isUsing(String userID){

boolean isUsing = false

Enumeration e = loginUsers.keys();

String key = ""

while(e.hasMoreElements()){

key = (String)e.nextElement();

if(userID.equals(loginUsers.get(key))){//hashTable에 저장된 키값을 받는다는 것은

//키 값에 포함된 Value 값을 받는 것(즉, 사용자ID)

isUsing = true

}

}

return isUsing;

}

//세션 생성

public void setSession(HttpSession session, String userID){

loginUsers.put(session.getId(), userID) //[1] 세션 ID를 가져오고, [2] 사용자 ID를 가져와서 대입.

session.setAttribute("login", this.getInstance()); //세션의 속성에 로그인매니져의 정보를 설정합니다.

}

//세션 성립될 때

public void valueBound(HttpSessionBindingEvent event){ // 로그인 할때

}

//세션 끊길때

public void valueUnbound(HttpSessionBindingEvent event){ //로그아웃 할때

loginUsers.remove(event.getSession().getId());//이벤트가 발생을 시킨 세션의 ID 값을 가져와서 HashTable

//데이터를 삭제합니다.

}

//세션 ID로 로긴된 ID 구분

public String getUserID(String sessionID){

return (String)loginUsers.get(sessionID);

}

//현재 접속자수

public int getUserCount(){ //몇 명의 사용자가 로그인 하고 있는지 계산합니다.

return loginUsers.size();

}

}

Bind_login.jsp

<%@ page contentType="text/html;charset=euc-kr" import="itexpert.chap05.LoginManager"%>

<% LoginManager loginManager = LoginManager.getInstance(); %>

<html>

<body>

<center>

현재 접속자수 : <%= loginManager.getUserCount() %><p>

<hr>

<%

if(loginManager.isLogin(session.getId())){ //세션 아이디가 로그인 중이면

out.println(loginManager.getUserID(session.getId())+"님 안녕하세요<br>"

+"<a href=Bind_logout.jsp>로그아웃</a>");

}

else{ //그렇지 않으면 로그인 할 수 있도록

%>

<form name="login" action="Bind_login_ok.jsp">

아이디: <input type="text" name="userID"><br>

비밀번회: <input type="text" name="userPW"><br>

<input type="submit" value="로그인">

</form>

<% }%>

</center>

</body>

</html>

Bind_login_ok.jsp

<%@ page contentType="text/html;charset=euc-kr" import="itexpert.chap05.LoginManager"%>

<% LoginManager loginManager = LoginManager.getInstance(); %>

<%

request.setCharacterEncoding("euc-kr");

String userID = request.getParameter("userID");

String userPW = request.getParameter("userPW");

if(loginManager.isValid(userID, userPW)){ //ID와 비밀번호가 맞는지 확인합니다.

if(!loginManager.isUsing(userID)){//ID가 사용중인지 아닌지 판단합니다.

loginManager.setSession(session, userID); // 사용하지 않는다면, 현재 세션과 ID 저장

response.sendRedirect("Bind_login.jsp"); //다시 로그인 화면으로 이동합니다.

}

else{

//throw new Exception("이미 로그인중입니다.");

response.sendRedirect(request.getContextPath()+"/index.jsp");

}

}

else{

//throw new Exception("ID/PW 이상");

response.sendRedirect(request.getContextPath()+"/index.jsp");

}

%>

Bind_logout.jsp

<%@ page contentType="text/html;charset=euc-kr"%>

<%

session.invalidate();

response.sendRedirect("Bind_login.jsp");

%>

index.html

<%@ page language="java" contentType="text/html; charset=EUC-KR" import="itexpert.chap05.LoginManager"

pageEncoding="EUC-KR"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<%

LoginManager loginManager = LoginManager.getInstance();

%>

<!-- Sessin ID : <%= session.getId() %> -->

<script>

function isLoginUserForm() {

if(login.userID.value == "") {

alert ("ID를 입력하지 않았습니다.");

login.userID.focus();

return false

}

if(login.userPW.value == "") {

alert ("패스워드를 입력하지 않았습니다.");

login.userPW.focus();

return false

}

return true

}

</script>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">

<title>방명록 작성 실습 예제 v0.01</title>

</head>

<body>

<center>

<h1> 방명록 작성 실습 예제 v0.03(JSP+JDBC + Login) </h1>

</center>

<hr/>

본 실습을 문서를 참고하지 않고 다시 작성할 수 있을때까지 반복하여 수행한다.

<br>

<hr/>

<a href="guestController.do?action_code=insert&mode=1"> 방명록작성(JSP를 이용하여 오라클 DB에 자료를 입력하는 실습)</a>

<hr/>

<a href="guestController.do?action_code=select"> 방명록보기(JSP를 이용하여 오라클 DB를 조회하는 실습)</a>

<hr/>

<h3>현재 접속자 수 : <%= loginManager.getUserCount() %> </h3>

<hr>

<%

if( loginManager.isLogin(session.getId())) {

%>

<%= loginManager.getUserID(session.getId()) %> 님 안녕하세요

<br>

<a href="Bind_logout.jsp"> 로그아웃 </a>

<%

} else {

%>

<form name="login" action="Bind_login_ok.jsp" onsubmit="return isLoginUserForm();" >

아이디 : <input type="text" name="userID"> 비밀번호 : <input type="password" name="userPW">

<input type="submit" value="로그인" >

</form>

현재 버전에서의 아이디와 패스워드는 데이터베이스를 점검하지 않고 있음. <p>

그러나 동일한 이름의 아이디를 이용한 중복 로그인은 허용하지 않음.

<%

}

%>

</body>

</html>

 

'Languages > JSP' 카테고리의 다른 글

JSP - 스크립트 요소  (0) 2012.10.26
JSP - 데이터를 담는다! BEAN!  (0) 2012.10.26
JSP - 컴포넌트 - SmartEditor JSP에 적용하기  (5) 2012.10.26
JSP - 내장객체  (0) 2012.10.26
JSP - 파일 업로드  (0) 2012.08.25