[Spring] Interceptor

2024. 7. 6. 22:43BE/Spring

1. Interceptor란?

 

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

 

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

 

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

 

  Filter Interceptor AOP
구현 Jakarta.servlet.Filter org.springframework.web.servlet.HandlerInterceptor  
관리 컨테이너 Servlet Container Spring Container Spring Container (Root)
적용 위치 web.xml servlet-context.xml execution으로 설정된 공통 코드 메서드
적용 대상 설정 url url execution에서 설정된 메서드(인자), 클래스 등 다양
동작 순서 Dispatcher Servlet 전달 전후 Controller에게 전달되기 전후 Proxy 패턴의 형태로 메서드 앞에 실행
request/response 객체 조작 가능 여부 O X X
주요 역할 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>

 


나. Interceptor 구현

 

 

HandlerInterceptor (Spring Framework 6.1.10 API)

postHandle Interception point after successful execution of a handler. Called after HandlerAdapter actually invoked the handler, but before the DispatcherServlet renders the view. Can expose additional model objects to the view via the given ModelAndView.

docs.spring.io

 

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");
    }
}

 

 

 

Modifier and Type Method Description
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 컨트롤러 실행 전의 인터셉션 지점.
false 반환 시 request를 바로 종료.
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 컨트롤러의 성공적인 실행 후, view rendering 전에 호출.
void afterCompletion(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;
    }
}

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

 

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>

 


'BE > Spring' 카테고리의 다른 글

[Spring] ControllerAdvice  (0) 2024.07.06
[Spring] Java Config  (0) 2024.07.06
[Spring] AOP  (0) 2024.07.06
[Spring] Filter  (0) 2024.07.06
[Spring] Spring Web Application의 동작 원리  (0) 2024.07.06