Interceptor 란 Filter와 매우 유사한 형태로 존재 하지만, 차이점은 Spring Context에 등록 된다. AOP와 유사한 기능을 제공 할 수 있으면, 주로 인증 단계 를 처리하거나, Logging 를 하는데 사용한다. 이를 선/후 처리 함으로써, business logic과 분리 시킨다.
Spring Boot에서 인터셉터(Interceptor)는 요청을 처리하기 전과 후에 실행되는 코드로,
**컨트롤러(Controller)에 도달하기 전과 후에 사용자 지정 작업을 수행할 수 있습니다**.
인터셉터는 로깅, 인증, 인가, 데이터 변환 등의 공통 작업을 수행하는 데 사용됩니다.
인터셉터를 구현하려면
**`org.springframework.web.servlet.HandlerInterceptor`**
인터페이스를 구현하는 클래스를 작성해야 합니다. 이 인터페이스에는 세 가지 메서드가 있습니다
1. **`preHandle()`**: 컨트롤러가 실행되기 전에 호출되는 메서드입니다.
이 메서드는 요청을 가로채서 필요한 작업을 수행한 후,
요청 처리가 계속되어야 하는지 여부를 결정합니다.
반환 값이 **`true`**이면 요청 처리가 계속되며, **`false`**인 경우 요청 처리가 중단됩니다.
2. **`postHandle()`**: 컨트롤러 실행 후 호출되지만,
뷰(View)가 렌더링되기 전에 호출되는 메서드입니다.
이 메서드는 컨트롤러가 요청을 처리한 후에 필요한 후 처리 작업을 수행하는 데 사용됩니다.
3. **`afterCompletion()`**: 요청 처리가 완료된 후,
즉 뷰 렌더링이 완료된 후에 호출되는 메서드입니다.
이 메서드는 자원을 정리하거나 추가 로깅 등의 작업을 수행하는 데 사용됩니다.
인터셉터를 구현한 후에는 **`WebMvcConfigurer`** 인터페이스를 구현하는 구성 클래스를 작성하여
인터셉터를 등록해야 합니다. 이 구성 클래스에서 **`addInterceptors()`** 메서드를
오버라이드하여 인터셉터 인스턴스를 등록할 수 있습니다.
예를 들어 다음과 같이 인터셉터를 등록할 수 있습니다
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterceptor());
}
}
이렇게 하면 인터셉터가 Spring Boot 애플리케이션에서 활성화되어 요청 처리 전,
후에 실행됩니다. 필요에 따라 인터셉터를 여러 개 등록하거나,
특정 경로 또는 패턴에만 적용할 수도 있습니다.
인터셉터 구현 순서
1. HandlerInterceptor 를 구현한 클래스를 직접 정의 한다.
2. WebMvcConfigurer 인터페이스를 구현한 클래스를 정의하고 1 번에서 만든 클래스를
등록 해주어야 한다.
예시 코드 : 컨트롤러 만들어 주기
package com.example.demo10.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserController {
@GetMapping("/loginPage")
public String loginPage() {
return "login.html"; // 내부에서 이동
}
/**
* 인증된 사용자만 들어 올 수 있게 막을 예정
* AuthInterceptory 동작 시킬려면 주소 설계를 /auth/**
*/
@GetMapping("/auth/infoPage")
public String infoPage(HttpServletRequest request) {
// 테스트
// todo
// 1. 아래 부분 삭제 예정
// 2. 인터셉터가 동작 하도록 주소 변경 예정
// HttpSession session = request.getSession();
// Object principal = session.getAttribute("principal");
// if(principal == null) {
// return "redirect:/loginPage";
// }
System.out.println("여기 코드 실행 할려면 로그인 되야 함");
// 상대 위치 들었음 -- 현재 그 시점에서 맞게 설계
// 위치에서 상대 경로 찾을지 절대 경로 찾을지 결정
return "/info.html";
}
}
인터셉터 만들어 주기
package com.example.demo10.handler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
// AuthInterceptor 는 request 요청이
// 앞에 /auth/** 로 요청한 주소에서만 동작 하도록 설계 할 예정
@Component // IoC 처리 확인
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 세션 여부 확인
HttpSession session = request.getSession();
Object principal = session.getAttribute("principal");
if(principal == null) {
System.out.println("인증 안된 사용자");
response.sendRedirect("/loginPage");
return false;
}
return true;
}
}
인터셉터 등록하기
package com.example.demo10.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired // DI 적용
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 규칙
// 주소요청이 /auth/** 이 붙으면 AuthInterceptor 동작
// 하도록 구현 처리
registry.addInterceptor(authInterceptor)
.addPathPatterns("/auth/**");
}
}
시나리오 코드 1
package com.example.demo8.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // IoC 대상
public class PublicController {
// http:localhost:8080/hello
@GetMapping("/hello")
public String hello() {
System.out.println("Controller 에서 메서드 실행");
return "hello";
}
}
package com.example.demo8.handler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
*
* 인터셉터 만들기
* 1. HandlerInterceptor 구현 처리
* 2. 3 가지 메서드 기억
*/
// 어노테이션 사용하지 않았음 !!!
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("----------------");
System.out.println("Request URI : " + request.getRequestURI());
System.out.println("Request Method : " + request.getMethod());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
package com.example.demo8.handler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
*
* @author
* 1. WebMvcConfigurer 구현 처리 하기
* 2. addInterceptors 를 구현 해야 한다.
*/
@Configuration // 1개 이상 빈으로 등록 해야 할 때
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 우리가 직접 만든 인터셉터 구현클래스를 등록 처리 합니다.
registry.addInterceptor(new LoggingInterceptor());
}
}
코드를 DI 사용하는 걸로 변경해 보자.
package com.example.demo8.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
*
* @author
* 1. WebMvcConfigurer 구현 처리 하기
* 2. addInterceptors 를 구현 해야 한다.
*/
@Configuration // 1개 이상 빈으로 등록 해야 할 때
public class WebMvcConfig implements WebMvcConfigurer {
// DI를 사용하는 코드로 변경해 보자.
@Autowired // DI 적용
private LoggingInterceptor loggingInterceptor;
// public WebMvcConfig(LoggingInterceptor loggingInterceptor) {
// this.loggingInterceptor = loggingInterceptor;
// }
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 우리가 직접 만든 인터셉터 구현클래스를 등록 처리 합니다.
registry.addInterceptor(loggingInterceptor);
}
}