권예진
코딩 공부
권예진
전체 방문자
오늘
어제
  • 분류 전체보기 (57)
    • Git과GitHub (3)
    • 개발상식 (0)
    • Back-End (20)
      • JAVA (3)
      • Spring (2)
      • CI&CD (0)
      • 부스트코스 (15)
    • PS (20)
      • 백준 (20)
    • TIL (0)
    • 회고 (3)
      • 우아한테크코스 (3)
    • 개발 도서 (8)
      • 객체지향의 사실과 오해 (8)
      • 좋은 코드, 나쁜 코드 (0)
    • 일상 (2)
      • 내가 보려고 만든 맥북 꿀팁 (2)
    • etc (1)
      • C (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 프로젝트세팅
  • 스프링
  • 스프링부트
  • 자바
  • 윤성우의열혈C프로그래밍
  • ps
  • Jacoco
  • 백엔드
  • github-actions
  • 우아한테크코스
  • 객체지향의사실과오해
  • C언어
  • 우아한테크코스5기
  • 독서
  • 맥북
  • 우테코5기
  • github
  • 백준
  • 단계별로풀어보기
  • 우테코
  • 부스트코스
  • git

최근 댓글

최근 글

hELLO · Designed By 정상우.
권예진

코딩 공부

Back-End/Spring

[Spring] Interceptor

2023. 5. 8. 16:42
반응형

Interceptor란?

  • intercept의 사전적 의미 : 중간에 가로채다
  • HTTP 요청 처리 중에 발생하는 이벤트를 가로채고 처리하는 객체
  • 특정한 URL 패턴 또는 컨트롤러에 대해 공통으로 적용되는 작업을 수행할 수 있다.
  • 좀 더 정확하게 말하면, controller의 핸들러(클라이언트가 요청한 url에 따라 실행되는 메서드)를 호출하기 전과 후에 요청과 응답을 가로채서 원하는 동작을 추가할 수 있도록 해준다.
    (ex. 로그인 체크, 응답에서 알림 개수 조회)

동작 과정

Interceptor 동작 과정

 

구현방법

1. HandlerInterceptor 인터페이스 구현하기

  • Interceptor를 만드려면 HandlerInterceptor 인터페이스를 implement한 객체에
    preHandle(), postHandle(), afterCompletion() 메서드를 오버라이딩 하면 된다.
    • 참고로 HandlerInterceptorAdapter 추상 클래스를 오버라이딩해서도 만들 수 있었으나,
      현재 deprecated 되었다.
      (HandlerInterceptorAdapter 도 HandlerInterceptor 인터페이스를 implement하고 있다.)
public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, 
                         HttpServletResponse response, 
                         Object handler, 
                         @Nullable ModelAndView modelAndView) throws Exception {

    }

    default void afterCompletion(HttpServletRequest request, 
                              HttpServletResponse response, 
                              Object handler,
                              @Nullable Exception ex) throws Exception {
    }
}

preHandle(), postHandle(), afterCompletion() 메서드가 실행되는 시점

실행 시점

  • preHandle()
    • 핸들러 어댑터 호출 전에 호출된다. (컨트롤러 호출 전)
    • 요청정보를 가공하거나 추가하는 경우에 사용
    • ture를 리턴하게 되면 preHandle() 실행 후 핸들러에 접근
    • false를 리턴하게 되면 컨트롤러와 남은 인터셉트 (postHandle(), afterCompletion())가 실행되지 않음
  • postHandle()
    • 핸들러 어댑터 호출 후에 호출된다. (컨트롤러 호출 후) (뷰 랜더링 전)
    • 컨트롤러에서 예외가 발생하면 postHandle()은 호출되지 않는다.
    • 파라미터로 받은 ModelAndView 객체를 이용해서 Controller에서 View에 정보를 전달하기 위해 작업한 Model 객체의 정보를 참조하거나 조작할 수 있습니다.
    • 비동기적 요청 처리 시에는 처리되지 않는다.
  • afterCompletion()
    • 뷰가 랜더링 된 이후에 호출된다.
    • 요청 처리 중에 사용한 리소스를 반환해줄 때 사용할 수 있다.
    • 예외가 발생하면 항상 호출된다. 예외를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다.
    • 비동기적 요청 처리 시에는 호출되지 않습니다.

2. WebMvcConfigurer 인터페이스 구현하기

  • Interceptor가 작동하게 하려면 Interceptor를 구현한 클래스를 빈(Bean)을 등록해주어야 한다.
  • 이를 위해 WebMvcConfigurer 인터페이스를 implement한 클래스가 필요하다.
  • WebMvcConfigurer 인터페이스를 implement 한 클래스에 addInterceptors() 메서드를 오버라이딩하고, 클래스에 @Configuration 어노테이션을 붙여주면 된다.

 

예제코드

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Interceptor</title>
</head>
<body>
<ul>
    <h2>Interceptor 예시 페이지 입니다.</h2>
    <p class="handler" th:text="'handler (컨트롤러 메서드 명): ' + ${handler}"></p>
    <li class="postHandle" th:text="'postHandle 작동 여부 : ' + ${postHandle}"></li>
</ul>
</body>

실행된 핸들러 이름 (컨트롤러 메서드명)과 Interceptor의 postHandle() 작동 여부를 웹 페이지에서 확인할 수 있도록 html 작성

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ExampleInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/exclude");
    }
}
  • addInterceptor() 메서드를 오버라이딩해서 Interceptor 등록
  • .addPathPatterns("/**") 를 통해 모든 경로에서 Interceptor가 작동하도록 설정
  • excludePathPatterns("/exclude") 를 통해 “/exclude”를 제외할 경로로 지정
public class ExampleInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception 
    {
        System.out.println("\n-----------------------------");
        System.out.println("interceptor: preHandle() 호출됨");
        return !handler.toString().contains("includeFalse");
    }

    @Override
    public void postHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler, 
                           ModelAndView modelAndView) throws Exception 
    {
        System.out.println("interceptor: postHandle() 호출됨");
        if (modelAndView != null) {
            modelAndView.addObject("postHandle", "postHandle 작동");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request,  
                                HttpServletResponse response, 
                                Object handler, 
                                Exception ex) throws Exception 
    {
        System.out.println("interceptor: afterCompletion() 호출됨");
        System.out.println("-----------------------------");
    }
}
  • preHandle()이 false이면 컨트롤러도 실행되지 않고, postHandle(), afterCompletion()도 실행되지 않는다. 이를 확인하기 위해 handler (실행된 컨트롤러의 메서드)가 includeFalse()면 preHandle()이 false를 반환하도록 설정했다.
@Controller
public class ExampleController {

    @GetMapping("/include")
    public String include(Model model) {
        System.out.println("controller: include() 실행 중");
        System.out.println("controller: include() 실행 중");
        System.out.println("controller: include() 실행 중");
        model.addAttribute("url", "/include");
        model.addAttribute("handler", "include()");
        return "example";
    }

    @GetMapping("/include/true")
    public String includeTrue(Model model) {
        System.out.println("controller: includeTrue() 실행 중");
        System.out.println("controller: includeTrue() 실행 중");
        System.out.println("controller: includeTrue() 실행 중");
        model.addAttribute("url", "/include/true");
        model.addAttribute("handler", "includeTrue()");
        return "example";
    }

    @GetMapping("/include/false")
    public String includeFalse(Model model) {
        System.out.println("controller: includeFalse() 실행 중");
        System.out.println("controller: includeFalse() 실행 중");
        System.out.println("controller: includeFalse() 실행 중");
        model.addAttribute("url", "/include/false");
        model.addAttribute("handler", "includeFalse()");
        return "example";
    }

    @GetMapping("/exclude")
    public String exclude(Model model) {
        System.out.println("controller: exclude() 실행 중");
        System.out.println("controller: exclude() 실행 중");
        System.out.println("controller: exclude() 실행 중");
        model.addAttribute("url", "/exclude");
        model.addAttribute("handler", "exclude()");
        return "example";
    }
}

콘솔 창에서 실행중인 메서드가 무엇인지 보기 위한 코드가 있고,

웹 페이지에서 현재 url과 실행중인 메서드명을 보여주도록 Model에 붙였다.

http://localhost:8080/include 로 접속 시

Untitled

 

Untitled

http://localhost:8080/include/true 로 접속 시

Untitled

 

Untitled

http://localhost:8080/include/false 로 접속 시

Untitled

 

Untitled

http://localhost:8080/exclude 로 접속 시

Untitled

 

Untitled

반응형
저작자표시 (새창열림)

'Back-End > Spring' 카테고리의 다른 글

[Spring/SpringBoot] SpringBoot 프로젝트 세팅하기  (2) 2024.09.14
    'Back-End/Spring' 카테고리의 다른 글
    • [Spring/SpringBoot] SpringBoot 프로젝트 세팅하기
    권예진
    권예진

    티스토리툴바