지난 포스팅에서 세션에 대해서 알아보았다.
JAVA는 서블릿 패키지에서 세션을 사용할 수 있도록 제공하고 있다.
LoginController
@PostMapping("/login")
public String login(@Valid @ModelAttribute LoginForm form, HttpServletRequest request){
// DB에서 회원정보 조회 [ 비즈니스 로직 ]
Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
// 회원정보가 없는 경우
if(loginMember == null){
bindingResult.reject("loginFail","아이디 또는 비밀번호가 맞지 않습니다. ");
return "login/loginForm";
}
// 회원정보가 있는 경우
// 세션 생성
HttpSession session = request.getSession(true);
// 생성된 세션에 세션명과 회원정보 저장
session.setAttribute(SessionConst.LOGIN_MEMBER,loginMember);
// 홈페이지 경로로 리다이렉트
return "redirect:/";
}
로그인 url로 요청이 들어오면 LoginController의 login 메소드가 호출된다. ID/Password로 회원정보를 조회하고 회원정보가 있다면 HttpServletRequest 객체의 getSession 메소드를 호출한다. 이때 파라미터로 true를 넘긴다. Request 객체 안에는 클라이언트가 보낸 쿠키가 저장되어 있다. 쿠키 안에는 세션ID가 들어있는데 세션ID와 매핑되는 회원정보가 없는 경우, 파리미터를 true를 넘기면 세션을 새로 생성한다. 새로 생성된 세션은 HttpSession 객체로 반환되고 setAttribute 메소드로 속성명과 회원정보를 입력한다. 속성명과 회원정보를 매핑하여 저장한다는 의미는 단일 세션 하나에 다양한 정보가 저장될 수 있음을 의미한다. 회원정보를 가져올 수 있는 key값을 속성명으로 하여 저장한다.
랜덤하게 생성된 세션ID는 쿠키에 저장되어 클라이언트에 전달된다. 클라이언트는 리다이렉트된 홈페이지 경로로 받은 쿠키를 전송한다.
HomeController
@GetMapping("/")
public String homeLogin(HttpServletRequest request, Model model){
// 세션 조회
HttpSession session = request.getSession(false);
// 세션이 없다면 일반 홈페이지 경로로 이동
if(session == null){
return "home";
}
// 세션이 있다면 세션 객체에서 회원정보 조회
Member loginMember = (Member)session.getAttribute(SessionConst.LOGIN_MEMBER);
// 회원정보가 없다면 일반 홈페이지 경로로 이동
if(loginMember == null){
return "home";
}
// 회원정보가 있으면 로그인된 홈페이지 경로로 이동
model.addAttribute("member",loginMember);
return "loginHome";
}
Request 객체 안에는 클라이언트가 보낸 쿠키가 들어있다. 쿠키 안에 저장된 세션ID로 세션저장소에서 세션을 조회한다.
HttpServletRequest 객체의 getSession 메소드를 호출하는데, 이때는 파라미터로 false를 넘긴다. 세션 조회가 목적이지 생성이 목적이 아니므로 true가 아닌 false를 넘긴다. 조회에 성공하면 조회된 세션정보가 담긴 세션객체를 반환한다. 세션객체에는 세션ID, 생성시간, 마지막접근시간, 회원정보 등 다양한 데이터가 담겨있다. 회원정보를 가리키는 key를 파라미터로 전달하여 회원정보를 가져온다. 회원정보가 존재한다면 회원정보를 뷰템플릿으로 전달하여 로그인된 홈페이지 화면을 클라이언트에 전달한다.
과정을 간략히 정리하면 아래와 같다.
1) Request에 저장된 쿠키에서 세션ID를 가져온다.
2) 세션ID와 매핑되는 세션객체를 가져온다.
3) 세션객체에서 회원정보를 추출한다.
4) 회원정보를 뷰템플릿으로 넘긴다.
여기서 Spring은 1), 2), 3)을 자동화하는 어노테이션을 제공한다.
HomeController( @SessionAttribute 사용 )
@GetMapping("/")
public String homeLoginV3Spring(@SessionAttribute(name=SessionConst.LOGIN_MEMBER,required = false) Member loginMember, Model model){
if(loginMember == null){
return "home";
}
model.addAttribute("member",loginMember);
return "loginHome";
}
@SessionAttribute에 세션명을 설정하면, Spring이 알아서 HttpServletRequest 객체에서 세션객체를 조회하고 세션명으로 회원정보를 가져와 파라미터로 넘겨준다. 주의할 점은 세션객체 조회시 파라미터로 false를 전달하므로, @SessionAttribute는 세션조회시에만 사용해야 한다. 세션 생성과정에서는 사용하면 안 된다.
이렇듯, 세션이 정상적으로 조회되어 회원정보를 가져올 수 있게 되면, 클라이언트는 ID/Password 없이도 쿠키만으로 웹서비스에 접근할 수 있게 된다.
추가로 서블릿 세션에 적용가능한 몇가지 설정을 알아보자.
1) 쿠키를 지원하지 않는 브라우저를 위한 작업 종료하기
application.properties
server.servlet.session.tracking-modes=cookie
몇몇의 웹브라우저는 쿠키를 지원하지 않는다. 쿠키를 지원하는 웹브라우저든, 쿠키를 지원하지 않는 웹브라우저든, 첫 로그인 요청을 할때는 쿠키를 보내지 않는다. 그러므로 서버입장에서는 브라우저가 쿠키를 지원하는지, 지원하지 않는지 구분할 수가 없다. 그래서 서버는 브라우저에게 쿠키를 반환함과 동시에 리다이렉트 URL을 아래와 같이 보낸다.
http://localhost:8080/;jsessionid=F59911518B921DF62D09F0DF8F83F872
쿠키를 지원하지 않는 브라우저는 위 경로로 세션을 유지할 수 있다. 반면 쿠키를 가지고 있는 브라우저는 위 경로가 쓸데없이 길다랗다. 그래서 두번째 요청부터는 서버가 쿠키를 가지고 있는 브라우저에게는 세션ID가 제거된 URL을 반환하고 쿠키없이 계속 세션ID가 붙은채 요청하는 URL에게는 세션ID도 같이 URL로 전달한다.
이는 소수의 브라우저를 위한 배려와 같다. 그러므로 이와같은 작업을 끄고 싶다면 위 설정을 application.properties에 추가하면 된다.
2) 세션 타임아웃 설정하기
application.properties
server.servlet.session.timeout=1800
글로벌하게 모든 세션의 타임아웃을 한번에 설정하고 싶다면 위 설정을 추가하면 된다. 세션 만료시간은 세션에 마지막 접근을 한 시간을 기준으로 측정된다. 1800초는 30분이다. 서버에 마지막 접근을 한 뒤 30분이 지나면 세션은 자동으로 세션저장소에서 제거된다.
session.setMaxInactiveInterval(1800);
만약 특정 세션만 타임아웃을 설정하고 싶다면 아래와 같이 세션 객체의 setter 함수를 호출하면 된다. 적절한 시간이 설정되어야 메모리 관리를 효율적으로 할 수 있다.
참고자료
'SPRING > Spring MVC' 카테고리의 다른 글
[SpringMVC] 스프링 인터셉터(Interceptor)란? (0) | 2023.08.31 |
---|---|
[SpringMVC] 서블릿 필터(Filter)란? (0) | 2023.08.31 |
[SpringMVC] Session( 세션 )이란? (0) | 2023.08.30 |
[SpringMVC] Cookie ( 쿠키 ) (0) | 2023.08.30 |
[SpringMVC] 검증(Validation)(8) - Bean Validation ( 폼객체 ) (0) | 2023.08.30 |