[본 포스팅은 스프링 MVC 2편 백엔드 웹 개발 핵심 기술 편을 기반으로 작성하였습니다.]
인터셉터란?
웹과 관련된 공통 관심 사항을 효과적으로 해결할 수 있는 기술이다.
즉, 인터셉터의 뜻처럼 사용자로부터 서버에 들어온 요청 객체가 핸들러까지 가기 전에 개발자가 추가적인 작업을 할 수 있다.
이 포스팅에서는 로그인이 되어 있지 않은 사용자가 상품에 대한 요청을 할 때 로그인 페이지로 돌려보내는 작업을 해볼 것이다.
홈페이지를 구축할 때 기능이
- 로그인
- 회원가입
- 상품 올리기
- 상품 수정 및 삭제
- 상품 목록
이렇게 다섯 가지 기능이 있다고 가정하면 상품에 대한 기능은 로그인을 한 유저만 접근이 가능하게 해야 할 것이다.
그러기 위해선 스프링 인터셉터를 적용해야 한다.
서블릿 필터와 비슷한 기술이지만 더욱 편리하고 정교하고 다양한 기능을 지원한다.
- 인터셉터의 호출은 세 단계로 잘 세분화되어 있다. (서블릿 필터는 단순히 doFilter()만 제공)
- 인터셉터는 어떤 컨트롤러가 호출되는지 정보를 받을 수 있다.
- 어떤 ModelAndView가 반환되는지 응답 정보도 받을 수 있다.
그냥 스프링 인터셉터를 사용하면 된다.
스프링 인터셉터의 호출 흐름은 다음과 같다.
- preHandle: 컨트롤러 호출 전에 호출된다.
- preHandle의 응답 값이 true면 다음으로 진행하고, false면 더는 진행하지 않는다. - postHandle: 컨트롤러 호출 후에 호출된다.
- afterCompletion: 뷰가 렌더링 된 이후에 호출된다.
기본적인 인터셉터의 구조
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
public static final String LOG_ID = "logId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
String uuid = UUID.randomUUID().toString();
request.setAttribute(LOG_ID, uuid);
//@RequestMapping: HandlerMethod
//정적 리소스: ResourceHttpRequestHandler
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;//호출할 컨트롤러 메서드의 모든 정보가 포함되어 있다.
}
log.info("REQUEST [{}][{}][{}]", uuid, requestURI, handler);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle [{}]", modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
String requestURI = request.getRequestURI();
Object logId = (String) request.getAttribute(LOG_ID);
log.info("RESPONSE [{}][{}][{}]", logId, requestURI, handler);
if (ex != null) {
log.info("afterCompletion error!!", ex);
}
}
}
이렇게 인터셉터는 앞서 말한 것처럼 총 세 가지로 preHandle, postHandle, afterCompletion으로 이루어져 있는데 코드를 실행시켜 보면
preHandle -> postHandle -> afterCompletion 순으로 실행된다.
강의에서 로그인 시에만 상품에 접근할 수 있게 하기 위해 preHandle을 사용해 볼 것이다.
로그인 체크 인터셉터 로직
LoginCheckInterceptor.java
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("인증 체크 인터셉터 실행 {}", requestURI);
HttpSession session = request.getSession();
if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) {
log.info("미인증 사용자 요청");
//로그인으로 redirect
response.sendRedirect("/login?redirectURL=" + requestURI);
return false;
}
return true;
}
}
먼저 로그인 체크 인터셉터 코드를 작성한다.
코드를 읽어보면 만약 세션 값(쿠키)이 없거나 세션의 속성 값 중 LOGIN_MEMBER가 없으면
response.sendRedirect로 로그인 창으로 보낸다.
참고로 sendRedirect는 로그인 성공 시 다시 이 페이지로 돌아오게 해 준다!(사용자가 편리)
웹과 관련된 설정 정보에 인터셉터 정보 추가
WebConfig.java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**", "/*.ico", "/error");
registry.addInterceptor(new LoginCheckInterceptor())
.order(2)
.addPathPatterns("/**")
.excludePathPatterns("/", "/members/add", "/login", "/logout", "/css/**", "/*.ico", "/error");
}
}
addInterceptors의 함수 안에 인터셉터들을 넣을 수 있다.
registry.addInterceptor(new 인터셉터 클래스명))
.order(순서)
.addPathPatterns(인터셉터를 적용할 URL 패턴)
.excludePathPatterns(인터셉터에서 제외할 패턴)
이렇게 등록해 주면 된다.
(참고로 위 코드는 인터셉터의 기본 구조를 볼 수 있는 LogInterceptor와 로그인 체크하는 인터셉터 LoginCheckInterceptor 두 개를 사용해 봤다.)
'JAVA > Spring' 카테고리의 다른 글
[Thymeleaf/JS] 부모 창에서 자식 창을 띄우고, 자식 창 데이터를 부모 창의 필드에 채워보자! (feat. 가져온 값이 눈에는 보이는 (0) | 2022.10.18 |
---|---|
[Spring/Thymeleaf] 타임리프로 팝업창 띄워보기 (feat. div 수직 중앙 정렬) (0) | 2022.10.14 |
[Spring] 로그인에 필요한 쿠키, 세션 생성 및 사용법 (서블릿 HTTP 세션) (1) | 2022.09.20 |
[Spring] Bean Validation의 한계, 해결하기 위한 방법 두 가지(groups, Form 나누기) (0) | 2022.09.19 |
[Spring] Bean Validation이란? / 사용해보기 (0) | 2022.09.19 |