。゚(*´□`)゚。

코딩의 즐거움과 도전, 그리고 일상의 소소한 순간들이 어우러진 블로그

[네이버클라우드] 클라우드 기반의 개발자 과정 7기/웹프로그래밍

[NC7기-82일차(8월23일)] - 웹프로그래밍 63일차

quarrrter 2023. 8. 23. 14:37

서블릿 공부 ex09

서블릿 : 릿(조각)  // 웹앱은 서블릿으로 이루어진 하나의 큰 거.

 

*서블릿 컨테이너 보관소 - 3대 보관소

 

Servlet context :

웹앱 시작하면 servlet context 한 개가 생성됨. app 마다 한 개씩 있는 거임, 앱이 종료되면 사라짐 

두 사람이 공유할 데이터는 servlet context에 저장하면됨.

브라우저에 상관없이 모든 요청에서 공유할 작업이 있으면 servlet context에 저장하면됨.

servlet context - dao, service 객체 등 모든 사용자가 공유할 객체 

 

Http session : 로그인 정보, 중간 작업 결과 등 세션이 유지되는 동안 공유할 객체를 보관

 

Servlet Request: 요청하면 생겼다가 응답하면서 사라지고, 또 새 요청하면 또 생겼다가 응답하고 사라짐 

중간 작업결과 등 요청을 처리하는 동안  공유할 객체 보관. 요청을 담당하는 서블릿이 들어있는 보관소.,

Servlet response도 요청들어오면 생성되고 응답하면 사라지는데 response안에는 보관소메서드가 따로 없음.

 

// 1) ServletContext 보관소에 값 넣기
// => ServletContext 객체는 웹 애플리케이션이 시작될 때 생성된다.
ServletContext sc = this.getServletContext();
sc.setAttribute("v1", "aaa");

// 2) HttpSession 보관소에 값 넣기
// => HttpSession 객체는 웹 브라우저에서
//    '세션 아이디(예:고객번호, 스탬프 카드)'를 제공하지 않으면,
//    getSession()을 호출할 때 생성된다.
//    즉 이 요청을 한 클라이언트의 HttpSession 객체가 없다면 만들어준다.
// => 웹 브라우저에서 '세션 아이디'를 제공하면,
//    getSession()을 호출할 때 기존에 생성했던 세션 객체를 리턴한다.
//    즉 이미 이 클라이언트를 위해 만든 객체가 있다면 그 객체를 리턴한다.
HttpSession session = request.getSession();
session.setAttribute("v2", "bbb");

// 3) ServletRequest 보관소에 값 넣기
// => ServletRequest 객체는 클라이언트가 요청할 때마다 생성된다.
request.setAttribute("v3", "ccc");

response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = response.getWriter();

out.println("보관소에 값을 넣었습니다. - /ex09/s1");
// 1) ServletContext 보관소에 저장된 값 꺼내기
ServletContext sc = this.getServletContext();
String v1 = (String) sc.getAttribute("v1");

// 2) HttpSession 보관소에 저장된 값 꺼내기
// => 이 요청을 한 클라이언트의 HttpSession 객체가 없다면 만들어준다.
// => 이미 이 클라이언트를 위해 만든 객체가 있다면 그 객체를 리턴한다.
HttpSession session = request.getSession();
String v2 = (String) session.getAttribute("v2");

// 3) ServletRequest 보관소에 저장된 값 꺼내기
String v3 = (String) request.getAttribute("v3");

response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = response.getWriter();

out.println("보관소에 저장된 값 꺼내기 - /ex09/s2");
out.printf("v1 = %s\n", v1);
out.printf("v2 = %s\n", v2);
out.printf("v3 = %s\n", v3);

v3이 null 인 이유 는 ,,, 밑에 그림
v2 응답하면서 request 날라가서 v3 응답할때 새로운 세션임. 그래서 null 임.
웨일

브라우저를 새로 띄워서 세션이 다름 .  세션이 달라도 서블릿컨텍스트는 공유하기 때문에 v1은 값이 나오고 

http는 크롬이 아니라 웨일에서  만든 세션이기때문에 세션이 달라서 아무것도 안 들어있음. 그래서 v2 v3 null 임.

 

 

// 보관소에 값 넣기 - forward/include 서블릿끼리 ServletRequest 공유하는 것 테스트



쿠키

쿠키는 문자열만 전달 ~ 

객체를 전달하고 싶다면 json으로 문자열로 변환해서 전달해야함. 

로그인:  옛날엔 서버 하나에 사용자들이 접근하는 방식이었는데 jwt 방식도 있음
6 꺼내기: 쿠키 객체 리스트로 return , 클라이언트 웹브라우저에서 쿠키 보관함.

쿠키 보내기 

Cookie c1 = new Cookie("name", "hong");
// 프로토콜 예 => Set-Cookie: name=hong


// => 값은 반드시 문자열이어야 한다.
//    만약 문자열이 아닌 값을 보내려면 Base64와 같은 인코딩 기법을 이용하여
//    바이너리 데이터를 문자화시켜서 보내야 한다.
Cookie c2 = new Cookie("age", "20");
// 프로토콜 예 => Set-Cookie: age=20

Cookie c3 = new Cookie("working", "true");
// 프로토콜 예 => Set-Cookie: working=true

// => 또한 값은 반드시 ISO-8859-1 이어야 한다.
//    만약 UTF-8을 보내고 싶다면 URL 인코딩 같은 기법을 사용하여
//    ASCII 코드화시켜 보내야 한다.
Cookie c4 = new Cookie("name2", "홍길동");
// 프로토콜 예 => Set-Cookie: name2=홍길동

Cookie c5 = new Cookie("name3", URLEncoder.encode("홍길동", "UTF-8"));
// 프로토콜 예 => Set-Cookie: name3=%ED%99%8D%EA%B8%B8%EB%8F%99
// 한글을 utf-8로 바꾸고 %로 또 바꿈


// 쿠키를 응답 헤더에 포함시키기
response.addCookie(c1);
response.addCookie(c2);
response.addCookie(c3);
response.addCookie(c4);
response.addCookie(c5);

response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = response.getWriter();

한글 문자열 변환

jvm은 무조건 utf-16으로 사용(?)

*쿠키 꺼내기 (인코딩 값은 직접 디코딩 해야함)

// 쿠키 꺼내기
// => 쿠키를 이름으로 한 개씩 추출할 수 없다.
// => 한 번에 배열로 받아야 한다.
// => 요청 헤더에 쿠키가 없으면 리턴 되는 것은 빈 배열이 아니라 null이다.
// => 따라서 무조건 반복문을 돌리면 안된다.
//
Cookie[] cookies = request.getCookies();

response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = response.getWriter();

if (cookies != null) {
  for (Cookie c : cookies) {
    // 쿠키 값이 'URL 인코딩'한 값이라면
    // 개발자가 직접 디코딩 해서 사용해야 한다.
    // 쿠키 값에 대해서는 서버가 자동으로 디코딩 해주지 않는다.
    out.printf("%s=%s,%s\n",
        c.getName(),
        c.getValue(),
        URLDecoder.decode(c.getValue(), "UTF-8"));


* 쿠키 유효기간

    // => 유효기간을 설정하면 웹브라우저는 그 기간 동안 보관하고 있다가
    //    웹서버에게 쿠키를 보낸다.
    // => HTTP 응답 프로토콜

// 유효기간을 설정하지 않으면 웹브라우저가 실행되는 동안에만 웹서버에게 쿠키를 보낸다.
// => 웹 브라우저는 메모리에 쿠키를 보관한다.
Cookie c1 = new Cookie("v1", "aaa");

// 유효기간을 설정하면 웹브라우저를 종료해도 삭제되지 않는다.
// 단 유효기간이 지나면 웹서버에 보내지 않고 삭제한다.
// => 웹 브라우저는 로컬 디스크에 쿠키를 보관한다.
Cookie c2 = new Cookie("v2", "bbb");
c2.setMaxAge(30); // 쿠키를 보낸 이후 30초 동안만 유효

Cookie c3 = new Cookie("v3", "ccc");
c3.setMaxAge(60); // 쿠키를 보낸 이후 60초 동안만 유효


    // Set-Cookie: v1=aaa
    // Set-Cookie: v2=bbb; Max-Age=30; Expires=Wed, 08-Apr-2020 02:41:43 GMT
    // Set-Cookie: v3=ccc; Max-Age=60; Expires=Wed, 08-Apr-2020 02:42:13 GMT

*쿠키 범위

// 사용 범위를 지정하지 않은 쿠키
// => 쿠키를 발급한 서블릿과 같은 경로이거나 하위 경로의 서블릿을 요청할 때만
//    웹 브라우저가 서버에 쿠키를 보낸다.
// => 기본: /ex10
Cookie c1 = new Cookie("v1", "aaa");

// 사용 범위 지정
// => 쿠키를 발급한 서블릿의 경로에 상관없이 지정된 경로의 서블릿을 요청할 때
// 웹 브라우저가 서버에 쿠키를 보낸다.
Cookie c2 = new Cookie("v2", "bbb");
c2.setPath("/ex10/a");

Cookie c3 = new Cookie("v3", "ccc");
c3.setPath("/");

// 어~ 왜 쿠키의 경로를 적을 때 웹 애플리케이션 루트(컨텍스트 루트)까지 적나요?
// => 쿠키 경로는 서블릿 컨테이너가 사용하는 경로가 아니다.
// => 웹 브라우저가 사용하는 경로다.
// => 웹 브라우저에서 '/' 은 서버 루트를 의미한다.
// => 따라서 웹 브라우저가 사용하는 경로를 지정할 때는 조심해야 한다.
// '/'가 서버 루트를 의미하기 때문이다.
// => 그래서 쿠키의 경로를 지정할 때는 웹 애플리케이션 루트(컨텍스트 루트)를 정확하게 지정해야 한다.


// 쿠키를 응답 헤더에 포함시키기
response.addCookie(c1);
response.addCookie(c2);
response.addCookie(c3);
@WebServlet("/ex10/s22")  v1, v3
@WebServlet("/ex10/a/b/c/s23")  v1, v2 v3
@WebServlet("/ex10_1/s24") v3

세션 ,, 

세션 id는 쿠키로 주고 받음. 타임아웃 되면 새로 생성함. 

세션
=> 클라이언트를 식별하는 기술이다.
=> HTTP 프로토콜은 Stateless 방식으로 통신을 한다.
   즉 연결한 후 요청하고 응답을 받으면 연결을 끊는다.
   그래서 서버는 클라이언트가 요청할 때 마다 누구인지 알 수 없다.
=> 이를 해결하기 위해
   클라이언트가 접속하면 웹 서버는 그 클라이언트를 위한
   고유 번호를 발급(쿠키 이용)한다.
   이 고유 번호를 '세션 아이디'라 부른다.
=> 웹 브라우저는 세션 아이디를 쿠키에 보관해 두었다가
   그 서버에 요청할 때 마다 세션 아이디를 보낸다.
   왜? 세션 아이디는 쿠키이다.
=> 서버에서 클라이언트로 세션 아이디를 쿠키로 보낼 때 유효기간을 설정하지 않았기 때문에
   웹 브라우저를 종료하면 세션 아이디 쿠키는 삭제된다.
=> 세션 아이디 쿠키의 사용 범위는 애플리케이션 경로에 한정된다.
   예) /eomcs-java-web
   따라서 같은 웹 애플리케이션의 서블릿을 실행할 때는
   무조건 세션 아이디를 보낸다.

세션 아이디는 언제 발급하는가?
=> 새 세션을 생성할 때 세션 아이디를 발급한다.

언제 새 세션을 생성하는가?
=> 세션이 없거나 유효기간이 지난 경우, 
   request.getSesssion()을 호출할 때 생성한다.
=> 새로 세션을 생성하면 그 세션 ID를 쿠키로 웹브라우저에게 보낸다.
=> 세션이 없는 경우?
   클라이언트가 세션 아이디를 보내지 않을 때
=> 세션 유효기간이 지난 경우?
   세션을 생성한 후 서버에 설정된 시간이 지나도록
   클라이언트의 요청이 않으면
   서버는 세션을 무효화시킨다.

새로 세션을 안 만들면 응답헤더에 세션 아이디를 포함하지 않는다. 

 

// 세션 활용 

같은 클라이언트라면 (클라이언트가 보낸 서센id가 같다면) 같은 http session 객체를 사용하기 때문에 세션 객체를 통해 서블릿의 작업 결과를 공유할 수 있다.


// 세션(session)의 타임아웃 설정

 세션의 유효 시간(초)을 설정한다.
 => 클라이언트가 요청하는 순간부터 세션 시간을 카운트 한다.
 => 만약 10초 이내에 클라이언트의 요청이 없으면
    10초를 초과하는 순간 HttpSession 객체를 무효화시킨다.
    (어떤 서블릿을 요청하는 상관없다)
 => 10초 이내에 다시 클라이언트 요청이 있다면
    카운트를 0부터 다시 시작한다.
 => 예) 인터넷 뱅킹 에서 보통 세션 타임아웃을 10분으로 설정한다.
        클라이언트가 어떤 링크를 누르면 카운트는 다시 10분으로 초기화된다.
session.setMaxInactiveInterval(10); 초

타임아웃되면 새로운 세션이 시작됨. 그러면 기존 세션은 날라가고 그 안에 데이터도 날라감~

 

// 세션(session) 무효화시키기

HttpSession session = request.getSession();
session.invalidate(); // 세션을 무효화시킨다.