Interceptor

스프링 인터셉터

인터셉터란 스프링 필터와 유사하게 동작하며 각각의 시점들을 간섭할 수 있도록 만들어진 AOP 객체를 말한다. Spring에서는 인터셉터를 다음의 형태로 제공한다.

  • Interface HandlerInterceptor

  • Class HandlerInterceptorAdapter

간섭이란 해당 시점의 진행 상황을 살펴보거나 변조할 수 있도록 가로채는 것을 말한다. 간섭할 수 있는 시점은 다음과 같다.

  • preHandle : 요청이 핸들링(연결)되기 전. 즉, 컨트롤러 실행 전

  • postHandle : 요청이 핸들링(연결)된 후. 즉, 컨트롤러 실행 후

  • afterCompletion : 요청에 대한 처리가 최종적으로 완료된 후. 즉, View 생성 후

  • afterConcurrentHandlingStarted : Servlet 3.0부터 가능한 비동기 요청 처리 방식의 경우 postHandle, afterCompletion 대신 실행

인터셉터 클래스 작성 및 등록

인터셉터 클래스 생성

인터셉터는 다음과 같이 생성한다.

@Slf4j
public class TestInterceptor extends HandlerInterceptorAdapter{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{ 
        log.info("prehandle = {}", handler);
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle = {}, {}", handler, modelAndView);
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
        log.info("afterCompletion = {}, {}", handler, ex);
    }
    
}

인터셉터 등록

인터셉터는 요청에 대한 처리와 연관되어 있으므로 servlet-context.xml에 등록한다.

<interceptors>
    <interceptor>
        <mapping path="/**"/>
        <beans:bean class="com.hakademy.app.TestInterceptor"/>
    </interceptor>
</interceptors>

인터셉터를 등록하기 위한 코드들에 대한 설명은 다음과 같다.

  • <interceptors> : spring-mvc 태그. 인터셉터들을 등록하기 위한 영역

  • <interceptor> : spring-mvc 태그. 인터셉터 1개를 등록하기 위한 영역

  • <mapping> : spring-mvc 태그. 인터셉터가 간섭할 URL 패턴을 지정(spring-expression으로 설정)

  • <exclude-mapping> : spring-mvc 태그. 인터셉터가 간섭하지 말아야할 URL 패턴을 지정(mapping에서 제외)

  • <beans:bean> : spring-beans 태그. 인터셉터로 등록할 bean 설정

Mapping url 작성규칙

Interceptor의 Mapping을 작성할 때에는 다음의 내용을 유의해야 한다.

  • 기존 url-pattern 설정과 달리 와일드카드(*) 사용이 자유롭다.

  • 기존 url-pattern 설정과 달리 ** 사용이 가능하다.

매핑 작성 예시(1)

<mapping path="/member*"/>

위와 같이 path를 /member*로 지정하면 엔드포인트(end-point)는 /로 설정된다. 따라서 다음 주소들이 매핑된다.

  • /member

  • /member_info

  • /memberlist

*/를 포함하지 않기 때문에 다음 경로는 해당되지 않는다.

  • /member/info

  • /member/regist

  • /member/list

매핑 작성 예시(2)

<mapping path="/member/*"/>

위와 같이 path를 /member/*로 지정하면 엔드포인트(end-point)는 /member/로 설정된다. 따라서 다음 주소들이 매핑된다.

  • /member/info

  • /member/regist

  • /member/list

다음 주소들은 매핑되지 않는다.

  • /member

  • /member_info

  • /memberlist

  • /member/list/1

  • /member/search/module

매핑 작성 예시(3)

<mapping path="/member/**"/>

위와 같이 path를 /member/**로 지정하면 엔드포인트(end-point)는 /member/로 설정된다. **/를 포함할 수 있으므로 다음 주소들이 매핑된다.

  • /member/info

  • /member/regist

  • /member/list

  • /member/list/1

  • /member/find/id/test

다음 주소들은 매핑되지 않는다.

  • /member

  • /member_info

  • /memberlist

인터셉터 메소드 분석

인터셉터의 각각 메소드를 분석하여 어떠한 행위를 할 수 있는지 파악해본다.

preHandle

  • 반환 형태

    • boolean : 요청의 통과(continue) 여부를 반환할 수 있다. true 반환 시 통과 , false 반환 시 차단된다.

  • 매개 변수

    • HttpServletRequest : 요청 정보를 가지고 있는 객체이다.

    • HttpServletResponse : 응답 정보를 가지고 있는 객체이다.

    • Object : 실행될 대상의 정보를 가지고 있는 객체이다.(일반적으로 컨트롤러의 매핑 메소드)

postHandle

  • 반환 형태

    • void : 이 메소드는 어떠한 결과도 전달할 수 없다.

  • 매개 변수

    • HttpServletRequest : 요청 정보를 가지고 있는 객체이다.

    • HttpServletResponse : 응답 정보를 가지고 있는 객체이다.

    • Object : 실행된 대상의 정보를 가지고 있는 객체이다.(일반적으로 컨트롤러의 매핑 메소드)

    • ModelAndView : 처리 완료 후의 ModelView의 정보를 가진 객체이다.

afterCompletion

  • 반환 형태

    • void : 이 메소드는 어떠한 결과도 전달할 수 없다.

  • 매개 변수

    • HttpServletRequest : 요청 정보를 가지고 있는 객체이다.

    • HttpServletResponse : 응답 정보를 가지고 있는 객체이다.

    • Object : 실행된 대상의 정보를 가지고 있는 객체이다.(일반적으로 컨트롤러의 매핑 메소드)

    • Exception : 페이지 렌더링 시 발생한 예외 정보를 가진 객체이다.

afterConcurrentHandlingStarted

이 메소드는 현재 문서에서 다루지 않는다.

Object Handler의 활용

Handler를 이용하면 다음 작업들을 처리할 수 있다.

  • 실행될(또는 실행된) 대상의 유형 확인

  • 실행될(또는 실행된) 대상의 Annotation Type 확인

  • 그 외 해당 대상의 정보 분석(매개변수, 반환형, 이름, 등...)

Object Handler를 이용하여 대상의 Annotation 정보 읽어오는 코드

if(handler instanceof HandlerMethod){
    HandlerMethod hm = (HandlerMethod) handler;
    log.info("method name = {}", hm.getMethod().getName());
    log.info("method annotation = {}", hm.getMethodAnnotation(RequestMapping.class));
    //...(이후 원하는 조건 등을 구현)
}

이를 응용하면 Custom Annotation을 만들어두고 이를 검사하여 원하는 작업을 처리하도록 하는 등의 작업을 구현할 수 있다.

Last updated