세션생성,삭제하는 법
actionContext로 구하는 법과 SessionAware로 구하는 법,
httpServletRequest로 구하는 법을 정리합니다.
1. actionContext로 구하는 법
<세션생성>
import com.opensymphony.xwork.ActionContext;
Map session = ActionContext.getContext().getSession();
session.put("session_id", id);
<세션삭제>
Map session = ActionContext.getContext().getSession();
session.remove("session_id");
2. SessionAware 인터페이스를 구현하면 session을 얻을수 있다
<세션생성>
import com.opensymphony.xwork.ActionSupport;
import org.apache.webwork.interceptor.SessionAware;
import java.util.Map;
public class SampleForm extends ActionSupport implements SessionAware{
private Map session;
public String execute() throws Exception {
session.put("session-userid", id);
}
}
3. HttpServletRequest로 session 생성
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.ActionSupport;
public class RequestSessionTestAction extends ActionSupport {
private String id = null;
public String execute() throws Exception {
ActionContext ctx = ActionContext.getContext();
HttpServletRequest request = (HttpServletRequest)ctx.get(ServletActionContext.HTTP_REQUEST);
HttpSession session = request.getSession(false);
session.setAttribute("session-userid", id);
return SUCCESS;
}
}
출처 - http://hmgirl.tistory.com/35
===================================================================================
Session 생성
| HttpServlteRequest 객체의 getSession()메소드를 이용하여 Session객체를 획득할 수 있다.
▶ HttpSession getSession(boolean create) getSession(true)일 경우 해당 Session이 존재한다면 그 Session을 Return하고, Session이 존재하지 않는다면 새로운 Session을 생성한다. getSession(false)일 경우 해당 Session이 존재한다면 그 Session을 Return하지만, Session이 존재하지 않는다면 null을 Return한다.
▶ HttpSession getSession() getSession(true)와 동일함 |
|
public class LoginAction extends Action {
public ActionForward execute( HttpServletRequest request, HttpServletResponse response)throws Exception{
// 세션 생성 부분 session 이란 이름으로 세션 생성.
HttpSession session = request.getSession(true);
}
}
출처 - http://blog.naver.com/PostView.nhn?blogId=jkleehi&logNo=10034158477&redirect=Dlog&widgetTypeCall=true
===================================================================================
모든 세션을 가져오기
java 구문으로서 .java .jsp둘다 사용가능.
Enumeration 로 모든 세션의 이름을 받아 뿌려줬다.
Enumeration se = session.getAttributeNames(); while(se.hasMoreElements()){ String getse = se.nextElement()+""; System.out.println("@@@@@@@ session : "+getse+" : "+session.getAttribute(getse)); } |
출처 -
===================================================================================
흔히 invalidate()를 사용하면 세션객체가 메모리에서 사라지는 것으로 오해할 수 있다.
아마도 "소멸" 이라는 단어가 주는 느낌 때문에 그럴수도 있다.
하지만 자바의 기초를 되짚어 다시한번 생각해보자
JAVA라는 언어는 프로그래머가 메모리 관리를 주도할 수 없도록 가비지 컬렉션을 제공하지 않는가?
그렇다면 invalidate()는 세션객체 자체를 소멸시키는것이 아니라, 세션의 기능을 중단시키고
무효화 시키는것이라고 표현해도 될 것이다.
아래의 예제1을 보면 invalidate()메서드 수행후에도 세션아이디는 여전히 출력이 되기 때문이다.
[예제1]
<%@ page session="true" language="java" contentType="text/html; charset=EUC-KR"%>
<%
String id=session.getId();
out.print("생성된 세션 아이디는"+id+"<br>");
session.invalidate(); // 세션 무효화 시킴 !!
out.print("invalidate() 적용후에도 "+session.getId()+"<br>"); // invalidate() 실행 후에도 ID는 여전히 출력된다
// 즉 객체가 아직 소멸하지 않았다고 보아야 한다.
%>
소멸되지 않은 객체이긴 하지만 getSession(false)메서드에 의해 참조되어 질수도 없다 .
아래의 예제를 보자
[예제2]
<%@ page session="true" language="java" contentType="text/html; charset=EUC-KR"%>
<%
String id=session.getId();
out.print("생성된 세션 아이디는"+id+"<br>");
session.invalidate(); // 세션 무효화 시킴 !!
out.print("invalidate() 적용후에도 "+session.getId()+"<br>");
out.print(request.getSession(false).getId());
%>
request.getSession(false) 메서드는 기존에 존재하는 세션을 리턴받는 메서드인데,
이미 무효화된 세션객체를 리턴받으려고 하니 에러가 나는 것이다.
따라서 여기서 혼란을 일으킬수 있으므로 다음과 같이 정리하고 가자
invalidate()메서드는 객체를 메모리에서 삭제할수는 없지만 객체를 무효화 시켜버린다!!
따라서 참조당할 수 없으며, getId() 메서드이외에는 메서드호출 또한 불가하다.
메서드 호출에 대한 아래의 실험을 살펴보자
[ 첫번째 예제1 : 올바르게 실행 ]
<%@ page session="true" language="java" contentType="text/html; charset=EUC-KR"%>
<%
String id=session.getId();
out.print("생성된 세션 아이디는"+id);
session.setAttribute("memberID","zino"); // memberID 라는 변수에 zino라는 값을 부여하였다.
String memberID = (String)session.getAttribute("memberID");
out.print("세션에 부여된 memberID 변수값은 "+memberID+"입니다."); // 세션에 부여된 값을 가져올 수 있다.
%>
[ 두번째 예제1 : 에러 발생]
<%@ page session="true" language="java" contentType="text/html; charset=EUC-KR"%>
<%
String id=session.getId();
out.print("생성된 세션 아이디는"+id);
session.invalidate(); // 세션 무효화 시킴 !! 아랫줄 부터는 에러 발생 !!!!
session.setAttribute("memberID","zino"); // memberID 라는 변수에 zino라는 값을 부여하였다.
String memberID = (String)session.getAttribute("memberID");
out.print("세션에 부여된 memberID 변수값은 "+memberID+"입니다."); // 세션에 부여된 값을 가져올 수 있다.
%>
두번째 예제에서 확인했듯이, 무효화 선언 이후엔 이 세션 객체의 메서드를 더 이상 사용할 수 없다.
즉 세션객체가 역할을 상실한 상태를 일컬어 세션소멸이라고 한다.
개인적으로는 세션소멸보다는 "세션무효화"가 더 나을것 같다.
아마 그래서 메서드명도 invalid (효력이 없는) 으로 정했을지도 모른다는 생각이 든다 ^^
출처 - http://blog.naver.com/PostView.nhn?blogId=zino1187&logNo=110025698379&categoryNo=17&viewDate=¤tPage=1&listtype=0
===================================================================================
Staless 프로토콜
- 세션에 대해 알아보기전에 우리는 HTTP의 프로토콜 특징에 대해 알아보고자 합니다.
- HTTP 프로토콜을 기본적으로 클라이언트의 요청(request), 응답(response)로 구현되어 있습니다.
- 이 말은, 서버에 요청을 하고 응답을 받으면 서버와의 통신이 끊기게 되고, 서버에는 클라이언트의 어떠한 정보도 유지하지 않는다는 뜻입니다.
- 이것을 HTTP의 Staless특성인 즉, 비연결형 프로토콜이라고 합니다.
- 장점
- 프로토콜을 직관적으로 이해하기 쉽고, 구현이 단순합니다.
- 클라이언트의 요청에 대한 처리 결과를 응답으로 전송하고 나면 접속이 종료되기 때문에, 서버측 네트워크 자원의 효율 성이 증가합니다. 즉, 더 많은 클라이언트 요청을 처리 할 수 있습니다.
- 단점
- 각 클라이언트 요청마다 새로운 접속이 이루어지기 때문에 서버측의 네트워크 자원의 낭비가 적지만, 새로운 접속을 맺기 위해 발생하는 오버헤드 즉, 수행속도의 감소가 지속적으로 발생할 수 있습니다.
- 또한, 동일한 클라이언트가 접속하더라도, 이전의 정보가 남아있지 않아서 클라이언트의 정보에 대한 비교가 불가능 합니다.
세션 (HTTP Session)
▶가상의 접속 상태를 유지하기 위한 메카니즘입니다.
- HTTP세션이 종료되는 시점은, 클라이언트 세션 아이디가 무효화 되는 시점입니다. 이 시점은 로그 아웃 등을 할 때 종료된다고 보면 됩니다.
- 웹에서 세션을 사용하고 있다면, 반드시 세션을 종료하는(로그아웃) 방법도 제공을 해주어야 합니다.
- 일정 시간 동안 동일한 클라이언트로부터 요청이 발생하지 않는다면, 이 또한 세션이 종료되도록 할 수 있습니다. web.xml에 설정된 경우 <session-config> 의 <session-timeout>설정을 통해 시간 설정이 가능합니다.
쿠키
▶쿠키라는 것은 클라이언트의 상태 정보를 서버로 전송하기 위해 사용할 수 있는 방법 중의 하나로서 클라이언트에 저장되는 단순한 텍스트 입니다.
- 쿠키는 브라우저가 종료되더라도 정보가 사라지지 않습니다.
- 쿠키는 사용자가 컴퓨터를 켜든 끄든 하드디스크에 (상당기간) 저장되어 있습니다
- 왜? PC에 저장하는 걸까요?
- 그것은 HTTP 프로토콜이 'stateless' 프로토콜이기 때문입니다. 웹 브라우저가 웹 서버에 접속을 해서 어떤 문서나 파일을 요청하면 웹 서버는 요청 받은 내용을 보내준 다음 접속을 끊습니다.
즉, 접속을 한 '상태(state)'가 지속되지 않고 요청된 것만 처리한 뒤 연결을 끊는 거죠. 그러므로 웹 서버는 일단 요청된 내용들을 클라이언트에 보내고 나면 그 뒤 사용자가 접속을 하고 있는지 어떤지 알 수가 없습니다. - 나아가, 예전에 접속했던 클라이언트가 또 접속을 한 것인지 아닌지 등은 더더욱 알 수 없습니다. 그런데 웹 사이트를 운용하는 측에서는 어떤 사용자가 다시 방문을 했는지 와 같은 정보가 절실히 필요했고 바로 이런 점을 해결하기 위해, 즉 stateless한 http의 특징을 커버하기 위해 등장한 아이디어가 쿠키(Cookie)입니다.
- 쿠키의 아이디어는 간단합니다. 접속한 클라이언트의 하드디스크에 적당한 정보를 저장해 둠으로써 또 그 클라이언트가 접속한 경우 언제든지 하드디스크에 저장된 정보를 읽어 들여서 그 사용자를 인식할 수 있는 것입니다. '
- 상태'에 관한 점검을 언제든지 할 수 있는 것이죠.
- 쿠키에 저장되는 내용은 천차만별입니다. 간단하게는, 사용자가 어떤 페이지를 읽었고, 로그인 아이디가 뭐고, 이 메일 주소가 뭐고 등을 기록할 수도 있고, 사용자가 어떤 물품을 주문했는지, ip 주소가 뭐고, 어떤 사이트를 거쳐서 우리 사이트로 왔는지, 또는 서버에서 각 클라이언트를 식별할 특별한 정보를 기록하는 등, 거의 모든 형태의 정보를 저장할 수 있습니다.
- 사용자 처지에서는 사실 기분 나쁠 수 있습니다. 나도 모르게 나의 행동이 하나하나 기록되어 '파일'로 저장되고 있고, 그 파일이 다른 곳도 아닌 '내' 컴퓨터에 나도 모르게 저장된다는 것은 별로 좋은 느낌은 아니죠.
- 하지만, 쿠키 파일은 사용자가 컴퓨터를 끄든 켜든 하드디스크에 (상당 기간) 저장되어 있기 때문에, 언제든지 사용자가 다시 어떤 웹 사이트에 접속하면 쿠키에 저장해 놓은 정보를 읽어 들여서 여러 형태의 '맞춤화된' 서비스를 제공할 수 있습니다. 이를 테면, 로그인을 한 번만 하면 그 다음부터 안 해도 된다든지, 어떤 페이지를 "몇 번 보셨군요" 라고 알려준다든지 등이 가능합니다.
- JSP에서 쿠키 설정하는 방법
- 헤더에 직접 지정하는 방법
- HTTP 헤더를 이용한 쿠키 설정
- Set-Cookie : name = value; expires = date; domain = serverDomain;
- path = serverPath; secure(HTTPS)
- 쿠키를 추상화 시켜놓은 서블릿 API를 이용하는 방법
- 이것은 보다 객체 지향적인 방법으로 클라이언트와 서버간의 쿠키 데이터 전송을 위해 Set-Cookie와 쿠키 헤더를 추상화한 javax.servlet.http.Cookie 클래스를 사용합니다.
JSP에서의 세션 관리
▶HttpSession과 세션 관리
- HttpSession은 서블릿/JSP에서 세션을 유지하기 위해 필요한 일련의 작업을 단순화 혹은 추상화시켜 놓은 API라고 생각하면 될 것입니다.
- 세션을 유지할 때는 다음의 방법을 사용합니다.
- 최초의 클라이언트에서 요청할 때 세션 유지를 위해 HttpSession 객체를 생성하고 고유한 세션 아이디를 생성합니다.
- HttpSession session = request.getSession();
- getSession()메소드는 create가 true일 경우 클라이언트 요청에 대해 기존에 생성된 객체가 존재할 때는 해당 객체를 리턴하고, 그렇지 않으면 새로운 객체를 생성하여 리턴합니다.
- create가 false 인 경우에 요청에 대해 생성된 HttpSession객체가 존재할때 이를 리턴하고, 그렇지 않으면 null 을 리턴합니다.
- 일반적으로 getSession()메소드는 getSession(true)과 동일하다고 보면 도비니다.
- HttpSession 객체 생성시 자동으로 생성된 세션 아이디를 이후의 클라이언트 요청부터 요청에 포함하여 전송합니다.
- 세션이 시작된 이후의 모든 요청이 들어올 때 마다 서버가 클라이언트에 부여한 세션 아이디를 통해 세션을 유지하도록 합니다.
- [세션 테스트]
차암 쉽쬬잉~~~~~~~~~♬
★만약, 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()호출된다.
다음은 이를 이용한 동시 사용자및 중복 로그인 방지 프로그램이다.
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();
}
}
<%@ 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>
<%@ 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");
%>
<%@ 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>
출처 - http://kimjongyeol.tistory.com/94