[Spring] Interceptor

1. Interceptor란?

  • Controller가 요청을 처리하기 전/후 처리.
  • 공통 코드 사용으로 코드 재사용성 증가.
  • 로깅, 모니터링, 접근 제어 등 실제 비즈니스 로직과 무관한 기능들을 분리할 수 있다.

Filter와 AOP와 유사하지만 다르다.

이들과 다르게 Login Session 검증, Header 검증, JWT Token 검증 등 웹과 관련된 기능을 담당한다.

 FilterInterceptorAOP
구현Jakarta.servlet.Filterorg.springframework.web.servlet.HandlerInterceptor 
관리 컨테이너Servlet ContainerSpring ContainerSpring Container (Root)
적용 위치web.xmlservlet-context.xmlexecution으로 설정된 공통 코드 메서드
적용 대상 설정urlurlexecution에서 설정된 메서드(인자), 클래스 등 다양
동작 순서Dispatcher Servlet 전달 전후Controller에게 전달되기 전후Proxy 패턴의 형태로 메서드 앞에 실행
request/response 객체 조작 가능 여부OXX
주요 역할Spring에 무관한 웹 자원 처리Controller 관련 요청 및 응답 처리주로 Business Logic 처리 후 Controller 처리
용도사용자 인증, 권한 검사, 요청과 응답에 대한 로그, 문자열 인코딩, 웹 보안 관련 기능인증 프로세스(로그인, 사용자 권한 관리), 사용자 세션 처리, 프로그램 실행 시간 측정로깅, 트랜잭션, 에러 처리


2. 구현

가. 설정 파일

Interceptor를 구현하기 위해서는 servlet-context.xml에 추가해야 한다.

1) servlet-context.xml

<!-- servlet-context.xml -->
<beans:bean id="confirm" class="com.company.fia.AInterceptor"/>

<interceptors>
    <interceptor>

        <!-- <mapping path="/article/*"/> -->
        <mapping path="/article/write"/>
        <mapping path="/article/view"/>
        <mapping path="/article/modify"/>
        <mapping path="/article/delete"/>
        <!-- <exclude-mapping path="/user/log*"/> -->

        <!-- <beans:bean class="com.company.fia.AInterceptor"/> -->
        <beans:ref bean="confirm"/>
    </interceptor>
</interceptors>
Code language: HTML, XML (xml)

나. Interceptor 구현

HandlerInterceptor (Spring Framework 7.0.2 API)

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class AInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("Pre-handle");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("Post-handle");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("After completion");
    }
}
Code language: JavaScript (javascript)

Modifier and TypeMethodDescription
booleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)컨트롤러 실행 전의 인터셉션 지점.false 반환 시 request를 바로 종료.
voidpostHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)컨트롤러의 성공적인 실행 후, view rendering 전에 호출.
voidafterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)view rendering 완료 또는 예외 발생 후 호출.
public class ConfirmInterceptor implements HandlerInterceptor { 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSesssion session = request.getSession();
        MemberDto memberDto = (MemberDto) session.getAttribute("userinfo");
        if(memberDto == null) {
            response.sendRedirect(request.getContextPath() + "/user/login");
            return false;
        }
        return true;
    }
}
Code language: PHP (php)

로그인 안 하면 로그인부터 하도록 한다.

false 반환 시 request를 바로 종료한다.

이 경우 postHandleafterCompletion 메서드는 호출되지 않는다.


3. 처리 순서

하나의 요청에 복수의 Interceptor가 적용될 때 실행 순서에 주의해야 한다.

특히 afterCompletion의 실행 순서에 주의하자.

<!-- servlet-context.xml -->
<interceptors>
    <interceptor>
        <mapping path="/article"/>
        <beans:bean class="com.company.fia.AInterceptor"/>
    </interceptor>
        <interceptor>
        <mapping path="/article"/>
        <beans:bean class="com.company.fia.BInterceptor"/>
    </interceptor>
        <interceptor>
        <mapping path="/article"/>
        <beans:bean class="com.company.fia.CInterceptor"/>
    </interceptor>
</interceptors>
Code language: HTML, XML (xml)

댓글 남기기