상태유지(Cookie & Session)

2019. 6. 14. 12:59JAVA Back-End

HTTP는 상태 유지가 되지 않는 프로토콜.

client에 request에 response 하고 나면 해당 client와 연결을 지속하지 않고 끊어버린다..ㅜ

 

---> 이런 문제를 해결하기 위해 Cookie/Session이란 기술이 등장!

(상태 유지 : 해당 클라이언트가 로그인을 했던 지 어떤 쇼핑을 했던 지/ 두, 세 번째 로그인했을 때 이 클라이언트가 누구인 지 정보를 알게 한다거나 할 수 있다.)

 

Cookie 

- 정보를 사용자 컴퓨터에 저장

- 저장된 정보를 다른 사람/시스템에서 볼 수 있다는 단점. (공용pc/피씨방 등등에 정보를 남긴다..)

- 유효기간이 지나면 사라짐

 

Session

- 서버에 저장

- 서버가 종료되거나 유효시간 지나면 사라짐

 

쿠키의 동작 과정

세션의 동작 과정


Cookie

javax.servlet.http.Cookie

 

이름(name) - 값(value) 쌍으로 된 단순한 문자열로 저장.

"이름 - 값 쌍"이외에도 "도메인" / "경로" / "유효기간" / "보안" / "HttpOnly"속성을 저장할 수 있습니다.

쿠키는 영문, 숫자로만 저장. 한글로 저장하고 싶다면 인코딩해서 보내고 받아온 값은 디코딩해야한다.

 

서버에서 클라이언트의 브라우저로 전송되어 사용자 컴퓨터에 저장

저장된 쿠키는 해당 웹 페이지에 접속 시, 브라우저에서 서버로 쿠키 값 전송.

쿠키는 개수와 크기가 브라우저별로 제한  값을 다르게 가지고 있습니다.

  • 하나의 쿠키는 4KB로 제한
  • 브라우저는 각각 웹사이트당 20개 쿠키 허용
  • 모든 웹 사이트를 합쳐 최대 300개 허용
  • 클라이언트 당 쿠키의 최대 용량은 4KB * 300 = 1.2MB정도

 

쿠키 사용을 위한 package

 

javax.servlet.http.Cookie

// 쿠키는 이름과 값을 받아 생성하고, response에 담아서 클라이언트에게 전송
Cookie cookie = new Cookie(이름, 값);
response.addCookie(cookie);

/* 
클라이언트가 보낸(request) 쿠키 정보가 서버에서 읽기
getName(), getValue()메소드를 이용해 원하는 쿠키정보를 찾을 수 있다
*/
Cookie[] cokkies = request.getCookies();

/* 
쿠키는 Client가 소유하므로 서버에서 삭제불가.
클라이언트에게 쿠키 삭제 요청
쿠키는 같은 이름이 2개 가질 수 없다!
따라서 새로온 쿠키로 교체되는데 유지시간(setMaxAge)이 0이므로 삭제됨.
 */
Cookie cookie = new Cookie("이름", null); 
cookie.setMaxAge(0); 
response.addCookie(cookie);

setMaxAge()

: 유효기간 0 으로 지정하면 쿠키 삭제

 음수를 지정하면 브라우저 종료시 쿠키 삭제

 ex) 10분 : cookie.setMaxAge(10*60) 

      1주일 : cookies.setMaxAge(7*24*60*60)

 

javax.servlet.http.Cookie

Spinrg MVC에서 Cookie사용

@CookieValue 사용 

 

컨트롤러 메소드(@CookieValue(value="쿠키이름" , required=false, defaultValue="기본값") String 변수명)

처럼 컨트롤러 메소드의 파라미터로 @CookieValue사용해 원하는 쿠키정보를 파라미터 변수에 담아 사용.


Session

javax.servlet.http.HttpSession

 

Client가 Server에 request보내면 Server는 Client를 식별하는 session ID를 생성(중요)

Server는 생성된 session ID로 key/value를 이용한 저장소인 HttpSession을 생성.

Server는 session ID를 저장하고 있는 쿠키를 생성, Client로 전송

Client는 Server로 request를 보낼 때 session ID를 가진 쿠키를 전송

Server는 쿠키에 있는 session ID를 이용해 이전 request에서 생성한 HttpSession을 찾음.

 

/* 
			Session생성 및 얻기 
 parameter에 false로 전달하면, 이미 생성된 session이 있으면 반환하고 없으면 null반환
*/
HttpSession session = request.getSession(); // true를 넣어도 됨.
HttpSession session = request.getSession(false);

session.isNew(); //새로 생성된 세션인지 알 수 있는 메서드

/* 
 			 Session값 저장 
이름과 값의 쌍으로 Object가 세션 유지 기간동안 저장
*/
session.setAttribute(String name, Object value); 

/* 
 			 Session값 조회 
setAttribute로 저장된 자료를 getAttribute로 조회
리턴 값은 Object형이라 형변환!
name값으로 조회!
*/
String value = session.getAttribute("id");

/* 
 			 Session값 삭제 
name값에 해당하는 세션 정보를 삭제 - removeAttribute
모든 세션 정보를 삭제 - invalidate()
*/

 


Spring에서의 Session 

 

key-point

@SessionAttributes/ @ModelAttribute

@SessionAttribute

SessionStatus

 

GuestController.java

@Controller
@SessionAttributes("name")

public class GuestController{
	public String name(String name, Model model){
     // ...
     
     model.addAttribute("name", "JEAN");
     
     return "list";
    }
}

list.jsp

<html>
	<head>
    	<title>Session exan</title>
    </head>
    
    <body>
    	<span>SessionAttributes로 넘어온 name값 : ${name}</span>
    </body>
</html>

컨트롤러에서 지정.

 

1.컨트롤러 메소드가 생성하는 모델에서 @SessionAttributes에 지정한 이름과 같은 이름이 있는 것을 session(HttpSession)에서 저장 - View(JSP)에서 해당 모델을 참조해 기존 정보를 form에 뿌려줄 수 있게 하기 위함입니다.

 

2. @ModelAttribute에 지정된 parameter가 있을 때 이 parameter에 전달할 오브젝트를 session에서 가져온다.

 

3. 연속으로 클라이언트에서 submit이 request되면 중복 submit을 방지할 떄 사용

  - SessionAttributes을 담은 객체는 SessionStatus의 setComplete() 호출해주기 전까지 계속 담겨있다.

   

  참고 출처 : http://willrain.tistory.com/10

@SessionAttribute

메소드에서 적용. 메소드에 @SessionAttribute로 파라미터에 지정된 이름으로 등록된 session정보를 읽어와 변수에 할당합니다 

 

SessionStatus

컨트롤러 메서드 parameter로 사용할 수 있는 스프링 내장 타입.

@SessionAttributes에서 더 이상 필요 없는 attribute는 SessionStatus.setComplete(); 메소드로 제거해야 한다!

수동으로 제거하지 않으면 계속 남아 있는다.

 

list.jsp - View

		<c:if test="${sessionScope.isAdmin == 'true'}">
			<a href="delete?id=${guestbook.id}">삭제</a>
			<br>
			<br>
		</c:if>

*session.setAttribute("isAdmin", true);으로 session에 저장*

 

GuestbookController.java

	@PostMapping(path = "/write")
	// @ModelAttribute : @SessionAttributes파라미터로 지정된 이름과 같은
	public String write(@ModelAttribute Guestbook guestbook, HttpServletRequest request) {
		String clientIP = request.getRemoteAddr();
		System.out.println("clientIP: " + clientIP);
		guestbookService.addGuestbook(guestbook, clientIP);

		return "redirect:list";
	}

	@GetMapping(path = "/delete")
	public String delete(@RequestParam(name = "id", required = true) Long id,
			@SessionAttribute("isAdmin") String isAdmin, HttpServletRequest request, RedirectAttributes redirectAttr) {
		if (isAdmin == null || !"true".equals(isAdmin)) { // 세션값이 true가 아닐 경우
			redirectAttr.addFlashAttribute("errorMessage", "로그인을 하지 않았습니다.");
			return "redirect:loginform";
		}
		String clientIp = request.getRemoteAddr();
		guestbookService.deleteGuestbook(id, clientIp);
		return "redirect:list";
	}

GuestbookAdminController.java

@Controller
public class GuestbookAdminController {
	@GetMapping(path = "/loginform")
	public String loginform() {
		return "loginform";
	}

	@PostMapping(path = "/login")
	public String login(@RequestParam(name = "pwd", required = false) String pwd, HttpSession session,
			RedirectAttributes redirectAttr) {
		// 원래는 db에서 가져온 값이랑 검증해야하지만 여기선 1234라는 임의의 값으로!
		if ("1234".equals(pwd)) {
			// isAdmin이란 이름으로 true boolean값을 session에 저장.
			session.setAttribute("isAdmin", true);
		} else {
			// redirectAttr은 DispatcherServlet이 관리하는 FlashMap에 값 저장! -redirect 때 딱 한 번만 값을 유지할 목적으로 사용
			redirectAttr.addFlashAttribute("errorMessage", "암호가 틀렸습니다");
			return "redirect:/loginform";
		}
		return "redirect:/list";
	}

	@GetMapping(path = "/logout")
	public String logout(HttpSession session) {
		session.removeAttribute("isAdmin");
		return "redirect:/list";
	}
}

loginform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>관리자 로그인</h2>
	<br>
	<br> ${errorMessage}

	<form action="login" method="POST">
		PW: <input type="password" name="pwd"> <br> <input
			type="submit">
	</form>
</body>
</html>		

[ edwith - 웹프로그래밍 부스트코스 ] 를 개인적으로 공부하고 정리한 공간입니다. 잘못된 부분은 피드백 주시면 감사하겠습니다

 

'JAVA Back-End' 카테고리의 다른 글

REST API 와 URI 설계  (0) 2023.02.11
[Web API] Web API 정리  (0) 2019.03.09
[REST API] REST API인가? Web API인가?  (0) 2019.03.09
[JDBC] MySQL에서 JDBC 사용  (0) 2019.03.09
[JDBC] JDBC (Java Database Connectivity)  (1) 2019.03.06