일반적인 웹 페이지는 로그인한 사용자와 로그인하지 않은 사용자를 구분하여 역할에 맞는 기능을 제공해야한다.
먼저, 프론트 화면처리로 로그인하지 않은 사용자에게는 상품관리라는 버튼을 숨겨서 기능을 제공하지 않을 수 있지만, URL경로를 직접 호출하게 된다면 프론트 처리만으로는 서비스에 제한을 둘 수 없다.
이런 로그인 여부확인은 회원가입, 정보수정, 삭제 등등 많은 서비스에서 사용되는데 여러 곳에서 공통으로 사용되는 로직을 웹에서는 스프링인터셉터를 사용하여 웹과 관련된 공통 관심사를 처리할 수 있다.
서블릿 필터
- 필터는 서블릿 스펙의 일부로 스프링 MVC와는 독립적으로 동작하며 모든 요청에 대해 동작할 수 있다.
javax.servlet.Filter인터페이스를 사용한다.- 모든 HTTP요청에 대해 공통적으로 처리해야 할 로직이 있을 때 사용(인코딩설정, CORS, 로깅 등)
- 스프링 MVC이외의 서블릿이나 JSP와 같은 다른 기술과 함께 사용될 때 사용
- 서블릿 컨테이너 레벨에서 요청을 가로채고 처리해야할 때 사용
==서블릿이 지원하는 필터==
필터의 정상흐름
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러
필터의 제한흐름
HTTP 요청 -> WAS -> 필터 -> 서블릿 호출X
예를들어 필터에서 로그인되지않은 사용자라고 판단하면 서블릿을 호출하지않고 필터에서 옳바르지않은 요청에대한 응답을 처리할 수 있다.
==스프링 부트에서 필터 등록==
스프링에서 제공하는 FilterRegistrationBean을 사용하면 스프링 빈으로 필터를 편리하게 등록할 수 있다.
setFilter(new ExampleFilter()): 등록할 필터를 지정setOrder(1): 필터가 여러개 있을 때 동작 순서를 지정한다.addUrlPatterns("/*"): 필터를 적용할 URL패턴을 지정한다.
참고로 @ServletComponentScan, @WebFilter와 같은 어노테이션으로 필터를 등록할 수 있지만 이 경우에는 필터 순서 조절이 불가능하기때문에 FilterRegistrationBean을 사용하는 것을 권장한다.
==예제==
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean<MyFilter> testFilter() {
FilterRegistrationBean<MyFilter> filter = new FilterRegistrationBean<>();
filter.setFilter(new MyFilter());
filter.addUrlPatterns("/test");
return filter;
}
}
FilterRegistrationBean을 통하여 필터를 등록한다.
public class MyFilter implements Filter {
private int number = 0;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
number++;
System.out.println("필터 시작 " + number);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
number++;
HttpServletRequest request = (HttpServletRequest) servletRequest;
String requestURI = request.getRequestURI();
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setStatus(205);
System.out.println("요청 URI: " + requestURI);
System.out.println("doFilter " + number);
filterChain.doFilter(request, servletResponse);
}
@Override
public void destroy() {
System.out.println("필터 종료 " + number);
}
}
아무의미없는 필터를 구현한 클래스로 필터에 사용 시점마다 number변수에 +1을 해주며 doFilter에서 요청에 대한 URL을 출력하고 다음 필터 또는 컨트롤러를 호출하도록 한다.
필터 시작 1
...SPRING BOOT 실행로그 생략...
요청 URI: /test
doFilter 2
컨트롤러 1
스프링 부트애플리케이션이 올라가기전에 필터가 먼저 시작되고, 컨트롤러를 호출하기전에 필터가 사용되는 것을 실행결과를 통해 확인할 수 있다.
스프링 인터셉터
스프링 인터셉터도 서블릿 필터와 같이 웹과 관련된 공통 관심 사항을 효과적으로 해결하는 기술이다.
인터셉터는 스프링 MVC가 제공하는 기술로 몇 가지 차이점이있다.
==스프링 인터셉터 흐름==
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러
==스프링 인터셉터 제한 흐름==
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러 호출 X
스프링 인터셉터는 서블릿 필터보다 편리하고 더 정교한 다양한 기능을 지원한다.
인터셉터를 사용하기위해서는 HanlderInterceptor를 구현하면 된다.
preHandle()postHandle()afterCompletion()
서블릿 필터의 경우에는doFilter()메서드 하나만 제공되기때문에 컨트롤러가 호출되기 전에 사용되는 필터만 가능했지만,
인터셉터를 사용한다면 컨트롤러 호출 전, 호출 후, 요청완료 이후와 같이 세분화된 상태로 사용할 수 있다.
==스프링 인터셉터 예외==
preHandle은 컨트롤러 호출 전에 호출되기때문에 예외와 관계없다.postHandle은 컨트롤러에서 예외가 발생하면 호출되지 않는다.afterCompletion은 항상 호출되기때문에 어떤 예외가 발생됐는지 확인할 수 있다.
==스프링 인터셉터 등록==WebMvcConfigurer를 구현한 설정 클래스를 통해 인터셉터를 편리하게 등록할 수 있다.
InterceptorRegistry: 인터셉터를 등록하는 클래스addInterceptor(new ExampleInterceptor()): 인터셉터를 등록addPathPatterns("/**): 인터셉터를 적용할 URL패턴을 지정한다.excludePathPatterns(): 인터셉터에서 제외할 패턴을 지정한다.
참고
PathPattern에대한 공식문서
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/ web/util/pattern/PathPattern.html
'Framework > Spring' 카테고리의 다른 글
| [Spring] - API예외 처리를 이해하기위한 기본 개념! (2) | 2024.09.06 |
|---|---|
| [Spring] 쉬우면서 정확하게 익혀보는 필터와 인터셉터의 예외처리 흐름과 예외 페이지 응답 (0) | 2024.09.04 |
| [Spring] JdbcTemplate (0) | 2024.06.16 |
| Spring - 메시지 기능으로 HTML하드코딩 제거하기 (0) | 2024.04.23 |
| Spring MVC - @RequestMapping (0) | 2024.04.16 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!