2019. 6. 14. 12:59ㆍJAVA 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)
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 |