공통 관심사
스프링 인터셉터의 흐름
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러
스프링 인터셉터는 체인으로 구성되며, 중간에 인터셉터를 자유롭게 추가할 수 있다.
서블릿 필터와 스프링 인터셉터는 웹과 관련된 공통 관심사를 해결하기 위한 기술이며, 인터셉터가 좀더 구현하기 편리하다.
특별한 문제가 없다면 인터셉터를 사용하는 것이 좋다
스프링 인터셉터를 사용하기위한 인터페이스
3가지 메소드가 존재한다.
@Slf4j
public class LogIntercepter 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();
//요청 로그를 구분하기 위한 uuid
String uuid = UUID.randomUUID().toString();
/*
preHandle에서 지정한 값을 사용하기위해 request에 담아둔다
-> 호출 시점이 분리 되어 있어 함께 사용되지 않기 때문
*/
request.setAttribute(LOG_ID, uuid);
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("postHandler [{}]", 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.error("after completion 에러!!", ex);
}
}
}
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
//컨트롤러 호출전에만 호출되면 되므로,prehandle만 구현
@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("미인증 사용자 요청");
//로그인으로 리다이렉트
response.sendRedirect("login?redirectURL=" + requestURI);
return false;
}
return true;
}
}
인증이 필요한 컨트롤러 호출 전에 호출 되므로, preHandle 메소드만 구현하면 된다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//로그 출력 인터셉터
registry.addInterceptor(new LogIntercepter())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**", "/*.ico", "/error");
//로그인 체크 인터셉터
registry.addInterceptor(new LoginCheckInterceptor())
.order(2) //두번째로 작동
.addPathPatterns("/**") //모든 경로에 대해 적용
.excludePathPatterns("/", "/members/add", "/login", "/logout",
"/css/**", "/*.ico", "/error"); //단, 이경로는 인터셉터 제외
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new LoginMemberArgumentResolver());
}
addInterceptors() : 인터셉터를 등록하는 메소드
.excludePathPatterns: 인터셉터에서 제외할 url 경로를 상세히 지정할 수 있다.