MVC - Session


본 카테고리는 스프링 프레임워크를 다룬다.

좀 더 자세한 내용은 아래의 공식 사이트를 참고하자.

참고 스프링 프레임워크 공식 사이트


스프링 MVC 프레임워크의 세션

요즘엔 로그인 기능을 구현하고 로그인 상태를 유지하는 경우가 많다.

스프링에서 로그인을 유지하는 방법은 HttpSession 혹은 Cookie를 이용하는 방법이 있다.

HttpSession을 이용해 로그인 상태 유지하기

HttpSession을 사용하려면 아래 두 가지 방법 중 하나를 사용한다.

  • 요청 매핑 어노테이션을 적용한 메소드에 HttpSession 파라미터를 추가한다.
  • 요청 매핑 어노테이션을 적용한 메소드에 HttpServletRequest 파라미터를 추가한 뒤, HttpServletRequest를 이용해 HttpSession을 구한다.

첫 번째 방법을 사용한 코드는 아래와 같다.

1
2
3
4
@PostMapping
public String form(LoginCommand loginCommand, Errors errors, HttpSession session) {
// Session을 사용하는 코드
}

위의 예제 코드처럼 파라미터에 HttpSession이 존재하는 경우 스프링 MVC는 해당 컨트롤러의 메소드를 실행할 때 HttpSession 객체를 파라미터로 전달한다.

만약 HttpSession을 생성하기 전이면 새로 생성해서 전달해주고, 기존에 존재하는 경우 해당 HttpSession을 전달한다.

두 번째 방법을 사용한 코드는 아래와 같다.

1
2
3
4
5
6
@PostMapping
public String submit(LoginCommand loginCommand, Errors errors, HttpServletRequest req) {
HttpSession session = req.getSession();
// Session을 사용하는 코드
}
)

첫 번째 방법이 더 간결해 보이긴 하지만 매번 HttpSession을 생성하고, 두 번째 방법은 필요한 시점에만 생성할 수 있따는 차이점이 있다.

만약 세션을 해제하려면 아래와 같은 코드로 해제할 수 있다.

1
2
3
4
5
@RequestMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
// 리다이렉트 등의 후처리
}

인터셉터 : Interceptor

사용자의 로그인 여부를 판단하기 위해 세션에 저장된 값을 활용하는 것을 다뤄 보았다.

만약 로그아웃 상태에서 직접 비밀번호 변경 페이지에 접속했을 때, 정상적으로 페이지가 표시된다는 것은 이상한 현상이다.

로그인 기반 서비스에서 사용자가 로그인 상태인지 일일이 코드를 작성해서 검증하는 것은 매우 귀찮은 작업이며,

코드의 중복을 야기하고, 유지보수 비용의 증대를 불러올 수 있다.

위와 같이 다수의 컨트롤러에 대해 동일한 기능을 적용할 때 사용하는 기능으로 인터셉터가 있다.

HandlerInterceptor 인터페이스 구현

org.springframework.web.HandlerInterceptor 인터페이스를 사용하여 아래의 시점에 대해 공통 기능을 적용할 수 있다.

  • 컨트롤러(혹은 핸들러) 실행 전
  • 컨트롤러(혹은 핸들러) 실행 후, 뷰를 실행하기 전
  • 뷰를 실행한 이후

위의 세 가지 시점에 대해 처리하기 위해 HandlerInterceptor 인터페이스는 아래의 메소드를 정의하고 있다.

1
2
3
4
5
// 컨트롤러(혹은 핸들러) 실행 전
boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception;

preHandle() 메소드는 컨트롤러나 핸들러 객체를 실행하기 전에 필요한 기능을 구현할 때 사용한다.

추가적으로 리턴 타입이 boolean인 것을 확인할 수 있는데, false를 반환하면 다음 인터셉터가 동작하지 않는다.

1
2
3
4
5
6
// 컨트롤러(혹은 핸들러) 실행 후, 뷰를 실행하기 전
void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception;

postHandle() 메소드는 컨트롤러나 핸들러가 정상적으로 실행된 이후에 추가 기능을 구현할 때 사용한다.

만약 컨트롤러나 핸들러가 Exception을 발생시키면 postHandle() 메소드는 실행되지 않는다.

1
2
3
4
5
6
7
// 뷰를 실행한 이후
void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception;
)

afterCompletion() 메소드는 뷰가 클라이언트에 응답을 전송한 뒤에 실행된다.

컨트롤러나 핸들러의 실행과정에서 Exception이 발생하면 네 번째 파라미터인 Exception ex로 전달된다.

해당 Exception을 로그로 남기는 등의 후처리를 하기 적합한 메소드이다.

만약 Exception이 발생하지 않으면 null로 전달된다.

HandlerInterceptor 설정

HandlerInterceptor를 구현하였으면 아래와 같은 코드로 추가할 수 있다.

1
2
3
4
5
6
7
8
9
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(/* 적용할 인터셉터 객체 */)
}
}