인터셉터 (Interceptor)
클라이언트에서 특정 URL 요청시 DispatcherServlet 이 Controller 를 호출하기 이전에 해당 요청을 가로채는 역할을 수행한다.
인터셉터가 수행되는 흐름 세가지
- DispatcherServlet --> Controller : Controller 가 수행되기 이전에 호출된다.
- Controller --> DispatcherServlet : HandleAdapter 가 Handle() 을 호출하고, View 를 Render() 하기 이전에 호출된다.
- View --> DispatcherServlet : 핸들러가 실행되고, View 가 Rendering 되고 이후에 호출되는 HandlerInterceptor 의 콜백메소드이다.
그림으로 보자.
위의 그림처럼 총 인터셉터는 세가지의 기능을 수행한다.
- boolean preHandle()
- void postHandle()
- void afterCompletion()
boolean preHandle()
DispatcherServlet 은 모든 웹 요청은 진입점이다. 요청이 클라이은터로 들어오는 경우 컨트롤러를 요청에 보내주기 전에 중간에 요청을 가로챈다. 리턴타입이 불린인데, 그 이유는 해당 요청에 맞는 요청인지 틀린 요청인지 확인하여 이후에 postHandle() 과 afterCompletion() 메소드 수행여부를 결정한다. true 타입을 반환하면 그대로 컨트롤러는 해당 요청을 실행하고 구현된 나머지 인터셉터 메소드를 수행하는 반면에 false 를 반환하면 수행하지 않는다. false 를 반환하면 이후에 HttpServletResponse 로 redirect 여부를 결정한다. 왜냐하면 틀린 요청이 들어왔으니 그에 따른 로직을 처리해주어야 하기 때문이다.
void postHandle()
HandlerAdapter 가 핸들러를 호출하였지만 DispatcherServlet 이 아직 View 를 Rendering 하지 않을 때 호출된다. 해당 메소드에서는 뷰 페이지에서 사용될 수 있는 ModelAndView 객체에 속성을 추가하여 이용할 수 있다.
void afterCompletion()
핸들러가 실행되고, 뷰가 렌더링되면 호출되는 메소드이다.
구현
인터셉터를 구현하기 위해서는 두가지 방법이 존재한다.
- abstract class HandlerInterceptorAdapter
- interface HandlerInterceptor
하나는 추상메소드로 extends 해줘도 되고, 반대로 implements 로 인터페이스를 구현해도 된다.
인터페이스 HandlerInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package org.springframework.web.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; public interface HandlerInterceptor { boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; } | cs |
추상클래스 HandlerInterceptorAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package org.springframework.web.servlet.handler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.AsyncHandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } @Override public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } @Override public void afterConcurrentHandlingStarted( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { } } | cs |
위의 내용에 있다시피 하나는 인터페이스로 하나는 추상클래스로 존재한다. 그리고 실제 인터셉터를 쓰려고 한다면 아래와 같이 이용할 수 있다.
(1) 추상클래스를 통한 인터셉터 클래스 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class RequestProcessing extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } } | cs |
(2) 인터페이스를 통한 인터셉터 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class RequestProcessing implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } } | cs |
두 구현의 내용모두 오버라이딩되는 모습은 동일하다. 그럼, 이제 스프링의 servlet-context.xml 에 아래의 내용을 추가하면 된다. 우선 빈으로 xmlns:mvc 내용을 추가한다. 그리고 인터셉터 config 설정을 아래와 같이 하는데, beans:bean 을 인터셉터 클래스에 대해서 패키지 포함 전체 경로를 기입하고 mapping 은 클라이언트로부터 들어오는 요청 URL 에 대해서 인터셉터가 작동하는 경로를 기입한다. 그리고 exclude-mapping 은 제외할 URL 이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <beans:beans xmlns:mvc="http://www.springframework.org/schema/mvc"> <!----------------------------------------------------------------------------> <!-- 인터셉터 config 설정 --> <!-- Configuring interceptors based on URI --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/board/**" /> <mvc:exclude-mapping path="" /> <beans:bean class="edu.doubler.util.RequestProcessingURL"></beans:bean> </mvc:interceptor> </mvc:interceptors> | cs |
'Spring' 카테고리의 다른 글
20180705 properties 파일 사용기. (0) | 2018.07.05 |
---|---|
20180622 Spring Security (0) | 2018.06.22 |
20180408 패키지 구성 방법 두가지 (0) | 2018.04.08 |
20180319 Jackson JSON Java Parser API (0) | 2018.03.19 |
20180306 ContextLoaderListener & DispatcherServlet 이해 (0) | 2018.03.06 |