반응형
Interceptor란?
- intercept의 사전적 의미 : 중간에 가로채다
- HTTP 요청 처리 중에 발생하는 이벤트를 가로채고 처리하는 객체
- 특정한 URL 패턴 또는 컨트롤러에 대해 공통으로 적용되는 작업을 수행할 수 있다.
- 좀 더 정확하게 말하면, controller의 핸들러(클라이언트가 요청한 url에 따라 실행되는 메서드)를 호출하기 전과 후에 요청과 응답을 가로채서 원하는 동작을 추가할 수 있도록 해준다.
(ex. 로그인 체크, 응답에서 알림 개수 조회)
동작 과정
구현방법
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
로 접속 시
http://localhost:8080/include/true
로 접속 시
http://localhost:8080/include/false
로 접속 시
http://localhost:8080/exclude
로 접속 시
반응형
'Back-End > Spring' 카테고리의 다른 글
[Spring/SpringBoot] SpringBoot 프로젝트 세팅하기 (2) | 2024.09.14 |
---|