728x90
반응형
웹에서의 상태 유지 기술
- HTTP프로토콜은 상태 유지가 안되는 프로토콜입니다.
- 이전에 무엇을 했고, 지금 무엇을 했는지에 대한 정보를 갖고 있지 않습니다. (로그인, 장바구니 등)
- 웹 브라우저(클라이언트)의 요청에 대한 응답을 하고 나면 해당 클라이언트와의 연결을 지속하지 않습니다.- 이 클라이언트가 두 번째, 세 번째 요청을 할 때 누구인지 정보를 알게 하는 것
- 상태 유지를 위해 Cookie와 Session기술이 등장합니다.
쿠키(Cookie)와 세션(Session)
- 쿠키
- 유지해야 할 정보를 사용자 컴퓨터에 저장- 저장된 정보를 다른 사람 또는 시스템이 볼 수 있는 단점 (공용 PC에서...)
- 유효시간이 지나면 사라짐
- 세션
- 서버에 저장
- 서버가 종료되거나 유효시간이 지나면 사라집니다.
쿠키 동작 이해
- 클라이언트가 서버에 요청을 보냄
- 이 때 유지해야 할 정보가 있다면 서버는 유지할 정보를 가지고 쿠키를 생성
- 이 때 쿠키는 이름과 같은 값으로 구성되어 있고, 유지 시간 등의 정보를 가지게 됨
- 만든 쿠키는 반드시 응답 결과에 포함되어서 클라이언트에게 전송됨
- 그럼 클라이언트는 그 쿠키를 다른 요청에도 꼭 포함시켜서 서버에게 전송
- 서버는 이전에 만들어둔 쿠키를 검사하여 확인
- 있다면 이 사용자가 전에 접속한 사용자라든지, 이 사용자가 유지해야하는 정보를 알아낼 수 있음
세션 동작 이해
- 클라이언트가 요청했을 때 유지해야할 정보가 있다면,
- 서버는 세션키를 생성
- 세션키를 이용한 저장소를 하나 생성. 여기에 유지해야하는 정보를 저장
- 서버에서 세션키를 담은 쿠키 생성
- 저장소만 만들어놓고 끝나버리면, 다시 클라이언트가 요청했을 때 이 클라이언트의 저장소가 어떤 곳인지 서버가 알아낼 길이 없음
- 생성한 쿠키를 클라이언트에게 보내서, 클라이언트가 다시 요청할 때마다 그 쿠키를 가지고 오도록 함
- 그럼 서버는 이 쿠키로부터 세션키를 얻어냄
- 이 세션키에 해당하는 저장소를 찾아서 저장소의 정보를 사용. 또는 정보 저장.
- HttepSession 객체 : 세션의 정보를 담기 위해 생성
쿠키
정의
클라이언트 단에 저장되는 작은 정보으 ㅣ단위
클라이언트에서 생성하고 저장될 수 있고, 서버 단에서 전송한 쿠키가 클라이언트에 저장될 수 있다.
이용방법
- 서버에서 클라이언트의 브라우저로 전송되어 사용자의 컴퓨터에 저장
- 저장된 쿠키는 다시 해당 웹 페이지에 접속 시, 브라우저에서 서버로 쿠키 전송
- 쿠키는 이름(name)과 값(value) 쌍으로 정보를 저장
- 이름-값 쌍 외에도,
- 도메인(domain), 경로(path), 유효기간(max-age, expires), 보안(secure), HttpOnly 속성을 저장 할 수 있다
쿠키의 수와 크기에 제한
- 브라우저 별로 제한 값을 다르게 가진다
- 하나의 쿠키는 4K Byte 크기로 제한
- 브라우저는 각각의 웹사이트 당 20개의 쿠키를 허용
- 모든 웹사이트 합쳐 최대 300개 허용
- 그러므로 클라이언트 당 쿠키의 최대 용량은 1.2M Byte
쿠키에는 사용자에 대한 사용 정보가 들어있다. 해당 정보가 많아질 수록 보안에 취약.
또다르 이유는...
javax.servlet.http.Cookie
서버에서 쿠키 생성, Response의 addCookie 메소드를 이용해 클라이언트에게 전송
- 쿠키는 (이름, 값)의 쌍 정보를 입력하여 생성합니다.
- 쿠키의 이름은 일반적으로 알파벳과 숫자, 언더바로 구성합니다. 정확한 정의를 알고 싶다면 RFC 6265(https://tools.ietf.org/html/rfc6265) 문서 [4.1.1 Syntax] 항목을 참조하세요.
Cookie cookie = new Cookie(이름, 값);
response.addCookie(cookie);
클라이언트가 보낸 쿠키 정보 읽기
- 쿠키 값이 없으면 null이 반환됩니다.
- NullPointException 처리 꼭 하기
- Cookie가 가지고 있는 getName()과 getValue()메소드를 이용해서 원하는 쿠키정보를 찾아 사용합니다.
Cookie[] cookies = request.getCookies();
클라이언트에게 쿠키 삭제 요청
- 쿠키를 삭제하는 명령은 없다. 쿠키는 웹 클라이언트가 관리하기 때문.
- 똑같은 이름의 쿠키를 생성하여, 보내주기.
- 즉, 클라이언트는 같은 이름의 쿠키를 가질 수 없다
- maxAge가 0인 같은 이름의 쿠키를 전송합니다.
- 유지시간을 0으로 주면 사라짐
Cookie cookie = new Cookie("이름", null);
cookie.setMaxAge(0);
response.addCookie(cookie);
쿠키의 유효기간 설정
- 메소드 setMaxAge()
- 인자는 유효기간을 나타내는 초 단위의 정수형
- 만일 유효기간을 0으로 지정하면 쿠키의 삭제
- 음수를 지정하면 브라우저가 종료될 때 쿠키가 삭제 - 유효기간을 10분으로 지정하려면
- cookie.setMaxAge(10 * 60); //초 단위 : 10분
- 1주일로 지정하려면 (7*24*60*60)로 설정합니다.
Spring MVC에서 Cookie 사용
- @CookieValue 애노테이션 사용
- 컨트롤러 메소드의 파라미터에서 CookieValue애노테이션을 사용함으로써 원하는 쿠키정보를 파라미터 변수에 담아 사용할 수 습니다. - 컨트롤러 메소드
- (@CookieValue(value="쿠키이름", required=false, defaultValue="기본값") String 변수명)
실습 1
guestbook 프로젝트를 이용
GuestbookController.java의 list 메소드를 다음과 같이 수정
package kr.or.connect.guestbook.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.or.connect.guestbook.dto.Guestbook;
import kr.or.connect.guestbook.service.GuestbookService;
@Controller
public class GuestbookController {
@Autowired
GuestbookService guestbookService;
@GetMapping(path="/list")
public String list(@RequestParam(name="start", required=false, defaultValue="0") int start,
ModelMap model,
HttpServletRequest request,
HttpServletResponse response) {
// 클라이언트가 서버에 요청 했을 때
// 실제 이 클라이언트가 내가 원하는 쿠키를 가지고 있는가? 먼저 확인하기
String value = null;
boolean find = false;
Cookie[] cookies = request.getCookies(); // 클라이언트로부터 쿠키 배열을 얻옴
if (cookies != null) { // 반드시 null 값 처리
for (Cookie cookie : cookies) {
if ("count".equals(cookie.getName())) {
find = true;
value = cookie.getValue();
break; // 쿠키를 하나만 찾고 그만 찾아도 된다면 적어주기
}
}
}
if (!find) // 처음 요청이 들어왔을 때
value = "1"; // 쿠키에 문자열 value를 넣을 수 있따
else { // 쿠키를 찾았다면
try {
int i = Integer.parseInt(value);
value = Integer.toString(++i);
} catch (Exception ex) {
value = "1";
}
}
// 변경된 쿠키 값을 클라이언트 쪽에 적용하게 하려면
// 반드시 쿠키는 매번 새로 만들어서 보내주어야 함
Cookie cookie = new Cookie("count", value); // 쿠키 생성
cookie.setMaxAge(60*60*24*365); // 1년 동안 유지 (유지 시간)
// -1을 주면 브라우저가 닫힐 때 쿠키도 없어짐. 브라우저를 껐다 켰을 때 다시 1 값으로 시작되게 됨
cookie.setPath("/"); // / 경로 이하에 모두 쿠키 적용
response.addCookie(cookie); // 응답 결과 보내주기
생략
// jsp에서 사용하도록 model에 넣어주기
model.addAttribute("list", list);
model.addAttribute("count", count);
model.addAttribute("pageStartList", pageStartList);
model.addAttribute("cookieCount", value);
return "list"; // list.jsp 뷰로 열기
}
list.jsp에 cookieCount 추가
<br> 방명록 전체 수 : ${count }, 방문한 수 : ${cookieCount }
실습 2 - @CookieValue
GuestbookController.java의 list 메소드의 입력값으로
@CookieValue 추가 후 불필요한 부분 삭제하기
@GetMapping(path="/list")
public String list(@RequestParam(name="start", required=false, defaultValue="0") int start,
ModelMap model,
@CookieValue(value="count", defaultValue="0") String value,
HttpServletRequest request,
HttpServletResponse response) {
/*
// 클라이언트가 서버에 요청 했을 때
// 실제 이 클라이언트가 내가 원하는 쿠키를 가지고 있는가? 먼저 확인하기
String value = null;
boolean find = false;
Cookie[] cookies = request.getCookies(); // 클라이언트로부터 쿠키 배열을 얻옴
if (cookies != null) { // 반드시 null 값 처리
for (Cookie cookie : cookies) {
if ("count".equals(cookie.getName())) {
find = true;
value = cookie.getValue();
}
}
}
if (!find) // 처음 요청이 들어왔을 때
value = "1"; // 쿠키에 문자열 value를 넣을 수 있따
else { // 쿠키를 찾았다면*/
try { // CookieValue를 찾고 null 값일 때의 지정값에 대해 안 적어도 된다
int i = Integer.parseInt(value);
value = Integer.toString(++i);
} catch (Exception ex) {
value = "1";
}
//}
생략
세션(Session)
정의
클라이언트 별로 서버에 저장되는 정보
로그인 정보, 장바구니 정보 등
이용 방법
- 웹 클라이언트가 서버측에 요청을 보내게 되면
- 서버는 이 클라이언트를 식별하는 session id를 생성 - 클라이언트마다 생성
- 서버는 session id를 이용해서 key와 value를 이용한 저장소인 HttpSession을 생성
- 서버는 session id를 저장한 쿠키를 생성하여 클라이언트에 전송
- 클라이언트는 서버측에 요청을 보낼때 session id를 가진 쿠키를 전송
- 서버는 쿠키에 있는 session id를 이용해서 그 전 요청에서 생성한 HttpSession을 찾고 사용
- HttpSession 객체는 서버가 알아서 만든다.
세션 생성 및 얻기
- request의 getSession()메소드는
- 서버에 생성된 세션이 있다면 세션을 반환하고 없다면 새롭게 세션을 생성하여 반환합니다.
- 기본값은 true
- 있다면 그 세션을 반환하고 없다면 null을 반환
- 새롭게 생성된 세션인지는 HttpSession의 isNew()메소드를 통해 알 수 있습니다.
HttpSession session = request.getSession();
HttpSession session = request.getSession(true);
- request의 getSession()메소드에 파라미터로 false를 전달하면, 이미 생성된 세션이 있다면 반환하고 없으면 null을 반환합니다.
HttpSession session = request.getSession(false);
세션에 값 저장
setAttribute(String name, Object value)
- name과 value의 쌍으로 객체 Object를 저장하는 메소드입니다.
- 세션이 유지되는 동안 저장할 자료를 저장합니다.
session.setAttribute(이름, 값)
세션에 값 조회
getAttribute(String name) 메소드
- 세션에 저장된 자료는 다시 getAttribute(String name) 메소드를 이용해 조회합니다.
- 반환 값은 Object 유형이므로 저장된 객체로 자료형 변환이 필요합니다.
- 메소드 setAttribute()에 이용한 name인 “id”를 알고 있다면 바로 다음과 같이 바로 조회합니다.
String value = (String) session.getAttribute("id");
세션에 값 삭제
- removeAttribute(String name) 메소드
- name 값에 해당하는 세션 정보를 삭제합니다. - invalidate() 메소드
- 모든 세션 정보를 삭제합니다.
javax.servlet.http.HttpSession
세션은 클라이언트가 서버에 접속하는 순간 생성
- 특별히 지정하지 않으면 세션의 유지 시간은 기본 값으로 30분 설정합니다.
- 세션의 유지 시간이란 서버에 접속한 후 서버에 요청을 하지 않는 최대 시간입니다.
- 30분 이상 서버에 전혀 반응을 보이지 않으면 세션이 자동으로 끊어집니다.
- 이 세션 유지 시간은 web.xml파일에서 설정 가능합니다.
<session-config>
<session-timeout>30</session-timeout>
</session-config>
실습
- /guess로 요청을 하면 컴퓨터가 1부터 100 사이의 임의의 값 중의 하나를 맞춰보라는 메시지가 출력합니다.
- 해당 값은 세션에 저장합니다.
- 사용자는 1부터 100 사이의 값을 입력합니다.
- 입력한 값이 세션 값보다 작으면, 입력한 값이 작다고 출력합니다.
- 입력한 값이 세션 값보다 크면, 입력한 값이 크다고 출력합니다.
- 입력한 값이 세션 값과 같다면 몇 번째에 맞췄다고 출력합니다.
guestbook 프로젝트의
controller 패키지에
GuessNumberController.java 추가하기
package kr.or.connect.guestbook.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class GuessNumberController {
@GetMapping("/guess")
public String guess(@RequestParam(name="number", required=false) Integer number,
HttpSession session, // Spring이 대신 생성
ModelMap model) { // 값을 저장하기 위 해 ModelMap 객체 생성
String message = null;
// get방식으로 /guess 를 요청하는데
// 파라미터 number가 없을 경우에는
// session에 count를 0으로 randomNumber엔 1~100사이의 값을 저장
if (number == null) { // 처음 요청이 들어왔을 때
session.setAttribute("count", 0);
session.setAttribute("randomNumber", (int)(Math.random()*100)+1);
message = "내가 생각한 숫자를 맞춰보세요";
} else {
int count = (Integer) session.getAttribute("count"); // Object로 반환되므로 형변환 필수ㅁ
int randomNumber = (Integer) session.getAttribute("randomNumber");
// 사용자가 보내준 값과 세션에 저장된 값을 비교
// number파라미터가 있을 경우
// 세션에서 값을 읽어들인 후, number와 세션에 저장된 값을 비교합니다.
// 값을 비교해서 작거나 크다면 카운트를 1 증가시켜주고
// 값이 같다면 세션 정보를 삭제합니다.
// 각 상황에 맞는 메시지를 message변수에 저장을 한 후 jsp에게 전달하기 위해서 ModelMap의 addAttribute메소드를 통해 전달하게 됩니다.
if(number < randomNumber) {
message = "입력한 값은 내가 생각하고 있는 숫자보다 작습니다.";
session.setAttribute("count", ++count);
}else if(number > randomNumber) {
message = "입력한 값은 내가 생각하고 있는 숫자보다 큽니다.";
session.setAttribute("count", ++count);
}else {
message = "OK " + ++count + " 번째 맞췄습니다. 내가 생각한 숫자는 " + number + " 입니다.";
session.removeAttribute("count"); // 세션 삭제
session.removeAttribute("randomNumber");
}
}
model.addAttribute("message", message);
return "guess";
}
}
view 폴더에 guess.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- JSLT 라이브러리 추가 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>숫자 맞추기 게임</title>
</head>
<body>
<h1> 숫자 맞추기 게임.</h1>
<hr>
<h3>${message }</h3>
<c:if test="${sessionScope.count != null}">
<form method="get" action="guess">
1부터 100사이의 숫자로 맞춰주세요.<br>
<input type="text" name="number"><br>
<input type="submit" value="확인">
</form>
</c:if>
<a href="guess">게임 다시 시작하기.</a>
</body>
</html>
참고
쿠키는 이름과 값이 모두 문자열 이지만,
세션의 키값은 문자열이고 값은 객체로 저장할 수 있다
728x90
반응형
'Web' 카테고리의 다른 글
[Postman] API 테스트 사이트 (0) | 2021.11.06 |
---|