화요일, 4월 23
Shadow

#026 세션관리

대화상태 유지하기

세션은 어떻게 작동하는가
1. 다이아나는 dark를 선택 한 다음 submit 버튼을 클릭합니다.
컨테이너는 BeerAPP서블릿의 새로운 스레드로 요청을 보냅니다.
BeerApp스레드는 다이아나의 세션을 찾아서 세션의 속성에 그녀가 선택한 Dark를 저장합니다.
2. 서블릿은 비즈니스 로직을 실행하고 응답합니다. 여기서 질문을 하나 더 하죠 생각하는 가격대는 어떻게 됩니까?
3. 다이아나는 페이지에 뿌려진 새오운 질문을 보고는 생각합니다. 그리고는 비싸다는 Expenseive를 선택하고는 submit 버튼을 클릭합니다.
컨테이너는 beerApp서블릿의 새로운 스레드로 요청을 보냅니다. BeerApp스레드는 다이아나의 세션을 찾아서 세션의 속성으로 그녀가 선택한 expensive를 저장합니다 .
4. 서블릿은 비즈니스 로직을 실행하고 응답합니다. 이 경우는 앞서한 질문에 대한 응답이겠죠
5. 다이아나의 세션은 여전이 활성화 상태입니다. 테리가 pale를 선택하고 submit버튼을 클릭합니다.
컨테이너는 테리의 요청을 beerApp서블릿의 새로운 스레드로 보냅니다.
BeeraApp서블릿의 스레드는 테리를 위한 새로운 새션을 만듭니다. 그리고 테리가 선택한 Pale을 저장하기 위하여 setAttribute()메소드를 호출합니다.

문제점 하나 – 컨테이너는 클라이언트를 어떻게 구분하는가?
클라이언트는 유일한 세션 ID가 필요하다.
클라이언트가 제일 처음 요청을 보낼때 컨테이너는 클라이언트의 유일한 세션ID를 생성하는거죠 그리고 이 값을 Response에 넣어 클라이언트로 보냅니다. 그러면 컨테이너는 ID를 받아보고 일치하는 세션과 요청을 연결합니다.

어떻게 클라이언트와 컨테이너는 세션ID정보를 공유하는가?
컨테이너가 거의 모든 쿠키고나련 작업을 합니다.
먼저 컨테이너에게 세션을 만들어 사용하고 싶다고 말을 합니다. 그러면 컨테이너가 세션ID를 생성하고 새로운 Cookie 객체를 만들죠 그러면 컨테이너는 쿠키안에 세션ID 값을 채우고, Response에 쿠키를 설정합니다. 그다음 클라이언트 요청부터는 컨테이너는 request객체에서 쿠키를 찾아서 세션ID를 가진 놈을 찾아서 세션과 요청을 연결합니다.

Response 객체와 세션 쿠키 보내기
HttpSession session = request.getSession();

Request객체로 부터 세션ID가져오기
HttpSession session  = requset.getSession();

새션이 이미 있었는지 아니면 금방 새로 만들어 졌는지는 어떻게 압니까?
HttpSession session = request.getSession();
if(session.isNew()){
out.println(“This is a new session”);
}
else{
out.println(“welcome back”);
}

새것 말고, 이미 만들어져 있는 세션을 원할때는?
HttpSession session = request.getSession(false);
if(session.=null){
out.println(“no session);
session = request.getSession();
}
else{
out.println(“there was a session “);
}

쿠키가 안될때 URL 재작성은 Response의 URL을 인코딩합니다.
쿠카가 작동하지 않으면, 컨테이너는 URL 재작성에 의지 할수밖에 없습니다. 그러나 response에 보내는 모든 URL을 인코딩을 인코딩하는 작업은 개발자가 해야 합니다 .
쿠키를 사용하는 거이 디폴트로 되어 있고 만약 이것이 작동하지 않으면 자동으로 URL 재작성이 사용되었으면 한다구요

public void doGet(HttpServletrequest request, HttpServletResponse response) throws IOException{
response.setContentType(“text/html”);
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
out.println(“<html><body>”);
out.println(“<a href=\””+response.encodeURL(“/beertest.do”); +”\”> click me+”</a>”);
out.println(“</body></html>”);

sendRedirect()로 URL을 재작성 합니다.
사용자로 부터 들어온 요청을 다른 서블릿이나 JSP로 보내고 싶은데 세션은 계속 유지 하고 싶을때
response.encodeRedirectURL(“/BeerTest.do”)
를 사용한다.

————————————————————-핵심정리
ㅇ URL 재작성은 요청으로 보낼때 HTML에 있는 모든 URL 끝에 세션 ID를 추가하는 방식이다.
ㅇ 사용자가  이 URL을 클릭하면 세션ID는 요청 URL의 끝에 보가 정보로 붙어서 돌아옵니다.
ㅇ URL 재작성은 쿠키 기능이 제고된 클라이언트를 위해 자동적으로 작동합니다. 그러나 개발자가 URL을 명시적으로 인코딩해야 합니다.
ㅇ URL을 인코딩하기 위해서는 response.encodeURL(aString)을 호출합니다.
ㅇ 정적인 페이지에 URL 재작성을 구현할 방법은 없습니다. 세션을 사용하고 싶다면 동적인 페이지를 사용합니다.

세션 제거하기
클라이언트가 사이트를 방문하고 세션이 시작되고 마음이 바뀌어 다른사이트로 가버리거나 또는 클라이언트가 사이트를 방문하고 세션이 시작되고갑자기 브라우저가 죽어버리거나 또는 클라이언트가 사이트를 방문하고, 세션이 시작되고 구매를 완료하거나, 또는 컴퓨터가 다운되거나..

어떻게 제가하면 될까?
1. 다이아나는 Dark를 선택하고 submit 버튼을 클릭합니다.
컨테이너는 접수한 요청을 BeerApp 서블릿의 스레드로 보냅니다.
컨테이너는 새로운 세션 ID #323 를 만듭니다. “JSESSIONID”쿠키를 Response에 넣어 다이아나에게 돌려 보냅니다.
2. 다이아나가 사라져 버렸습니다.
컨테이너는 쉬는시간에도 자신의 할일을 열심히 하겠죠
다이아나의 세션은 여전히 서버에 남아있습니다.
3. 시간이 지나도 다이아나는 돌아오지 않습니다.
컨테이너는 세션 #323의 상태를 체크해보고는 30분동안이나 들어온 요청이 없는것을 확인합니다.
컨테이너는 이렇게 되뇌이죠 컨테이너는 결국 세션을 제거합니다.

주요 HttpSession 메소드
getCreationTime()
– 새션이 생성된 시간을 리턴합니다.
getLastAccessedTime()
– 이세션으로 돌아온 마지막요청시간을 리턴합니다.
setmaxInactiveInterval()
– 해당 세션에 댛나 요청과 요청 시간의 최대 허용시간을 지정합니다.
getmaxInactiveInterval()
– 해당 세션에 대한 요청과 요청 시간의 최대 허용시간을 리턴합니다.
invalidate()
– 세션을 종료합니다.

새션타임아웃 설정하기
세션이 종료되는 세가지 이유 :
– 시간이 다외어서
– 개발자가 새션 객체에 invalidate() 메소드를 실행하는 경우
– 애플리케이션이 다운되는 경우

1. DD에서 세션 타임아웃을 설정하기
<web-app>
<servlet>
</servlet>
<session-config>
<session-timeout>15</session-timeout>
</session-config>
<web-app>

2. 특정세션만 타임아웃 서정하기
session.setmaxinaciveInterval(60*20);

서블릿 API로 쿠키 사용하기

Cookie 객체를 생성합니다.
Cookie cookie = new Cookie(“username”,name);
쿠키가 클라이언트에 얼마나 오래동안 살아있는지 설정합니다.
cookie.setmaxAge(60*30);
쿠키를 클라이언트로 보냅니다.
response.addCookie(cookie);
클라이언트 Request에서 쿠키를 읽어 드립니다.
Cookie[] cookies = request.getCookies();
for(int i = 0; i<cookies.length; i++){
Cookie cookie = cookies[i];
if(cookie.getName().equals(“username”)){
String userName = cookie.getvalue();
out.println(“Hello ” + userName);
break;
}
}

새션 생명주기 이벤트
생명주기
새션 생성, 새션 소멸  = HttpSessionEvfent, HttpSessionListener
속성
속성 추가, 속성 제거, 속성 대체 = HttpSessionBindingEvent, HttpSessionAttributeListener
이동
세션이 비활성화 되려고 할때, 세션이 활성화 될때 = HttpSessionEvent, HttpSessionActivationListener

새션 이동
동일한 클라이언트가 보낸 요청이 동일 서블릿의 서로 다른 이스턴스로 넘어간다는 것입니다. 즉 요청 A가 VM A상의 서블릿 A로갈수있고, 요청 B가 VM B에서 돌아가는 서블릿 A로 매핑될수도 있다는 것을 의미합니다.
오직 HttpSession 객체와 그 속성마이 하나의 VM에서 다른 VM으로 옮겨 갑니다.
그러나HttpSession은 웹 애플리케이션당 하나의 세션 ID당 하나밖에 없스니다. 이는 얼마나 많은 VM이 분산환경에서 돌아가든지 상관없습니다.

실제 세션 이동
1. 다이아나는 pale를 선택한후 submit버튼을 클릭합니다.
로드밸런싱 서버가 이 요청을 VM1에 있는 컨테이너 A-1으로 넘깁니다.
컨테이너는 새로운 세션, ID #323을 생성합니다. 다이아나에게 응답으로 “JSESSIONID”란 쿠키에 이번호를 돌려줍니다.
2. 다이아나는 Bitter를 선택한후 Submit 버튼을 클릭합니다.
이번에는 로드 밸런싱 서버가 이 요청을 VM2에 있는 컨테이너 A-2로 넘깁니다.
컨테이너는 요청을 접수하고 세션ID를 확인힙니다.세션ID323은 다른 VM, VM1에 있는것이란 것을 알고 다음과 같이 생각합니다.
3. 세션 #323을 VM1으로 부터 VM2로 옮깁니다. 이제 더이상 VM1에는 이 세션이 없고 VM2에만 존재하겠지요
세션을 옮긴다는 말은 VM1에는 비활성화 시키고 VM2에서 활성화 시킨다는 의미 입니다.
4. 컨테이너는 서블릿 A의 새로운 스레드를 만들고 접수한 요청을 방금 옮긴 #323과 연결합니다.
다이아나의 새로운 요청은 스레드로 보내지고, 모든 부분이 다 만족스럽습니다. 다이아나는 무엇이 일어났는지 아무것도 모르죠

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.