HttpServletRequest
를 제공, 웹과 관련된 부가적인 기능 제공필터 흐름
필터 제한
필터 체인
필터 인터페이스
doFilter()
: 고객의 요청이 올 때 마다 해당 메서드가 호출, 필터의 로직을 구현하면 됨필터 생성
implements Filter
chain.doFilter(request, response);
필터 등록
setFilter(new LogFilter())
: 등록할 필터를 지정setOrder(1)
: 필터의 순서 설정, 낮을 수록 먼저 동작addUrlPatterns("/*")
: 필터를 적용할 URL 패턴을 지정, 한번에 여러 패턴 지정 가능@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean logFilter(){
//필터를 사용하고 싶을 때 등록해서 사용
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LogFilter());
filterRegistrationBean.setOrder(1);
//순서
filterRegistrationBean.addUrlPatterns("/*");
//어떤 URL 패턴에 적용할 건지, /* 적용하면 모든 URL에 다 적용됨
return filterRegistrationBean;
}
}
LoginCheckFilter.java
if(isLoginCheckPath(requestURI)){
log.info("인증 체크 로직 실행 {}",requestURI);
HttpSession session = httpRequest.getSession(false);
if(session==null
||session.getAttribute(SessionConst.LOGIN_MEMBER)==null){
//로그인이 되지 않았을 때
log.info("미인증 사용자 요청 {}",requestURI);
//로그인으로 redirect, 로그인 하면 원래 접속하려던 페이지로
// 다시 돌아가게 하기위해 현재 페이지 정보를 넘김
httpResponse.sendRedirect("/login?redirectURL="+requestURI);
return; //여기가 중요, 미인증 사용자는 다음으로 진행하지 않고 끝!
}
}
whitelist = {"/", "/members/add", "/login", "/logout","/css/*"};
httpResponse.sendRedirect("/login?redirectURL=" + requestURI);
return;
LoginController.java
@PostMapping("/login")
public String loginV4(@Valid @ModelAttribute LoginForm form,
BindingResult bindingResult,
@RequestParam(defaultValue = "/") String redirectURL,
HttpServletRequest request){
...
return "redirect:"+redirectURL;
}
공통 관심사를 서블릿 필터를 사용해서 해결한 덕분에 향후 로그인 관련 정책이 변경되어도 필터만 변경하면 됨
스프링 인터셉터도 서블릿 필터와 같이 웹과 관련된 공통 관심 사항을 효과적으로 해결할 수 있는 기술이지만 순서, 범위, 사용방법이 다르고 더 많은 기능을 제공, 더 좋음
특별히 필터를 꼭 사용해야 하는 상황이 아니라면 인터셉터를 사용하는 것이 더 편리
스프링 인터셉터 흐름
스프링 인터셉터 제한
스프링 인터셉터 체인
스프링 인터셉터 인터페이스
스프링 인터셉터 호출 흐름
preHandle
: 컨트롤러 호출 전에 호출postHandle
: 컨트롤러 호출 후에 호출afterCompletion
: 뷰가 렌더링 된 이후에 호출 (완전히 응답이 난 다음에 호출)인터셉터 생성
LogInterceptor.java
HandlerInterceptor
를 구현request.setAttribute
, request.getAttribute
사용인터셉터 등록
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**","/*.ico","/error");
//excludePathPatterns > 이 경로는 제외
}
addInterceptors()
를 사용해서 인터셉터를 등록registry.addInterceptor(new LogInterceptor())
: 인터셉터를 등록order(1)
: 인터셉터의 호출 순서를 지정addPathPatterns("/**")
: 인터셉터를 적용할 URL 패턴을 지정excludePathPatterns("/css/**", "/*.ico", "/error")
: 인터셉터에서 제외할 패턴을 지정스프링의 URL 경로
?
: 한 문자 일치 /pages/t?st.html
*
: 경로(/) 안에서 0개 이상의 문자 일치 /resources/*.png
**
: 경로 끝까지 0개 이상의 경로(/) 일치 /resources/**
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String requestURI=request.getRequestURI();
log.info("인증 체크 인터셉터 실행 {}",requestURI);
HttpSession session=request.getSession();
if(session==null||session.getAttribute(SessionConst.LOGIN_MEMBER)==null){
log.info("미인증 사용자 요청");
//로그인으로 redirect
response.sendRedirect("/login?redirectURL="+requestURI);
return false; //문제가 될 때 종료
}
return true;
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginCheckInterceptor())
.order(2)
.addPathPatterns("/**") //모든 경로에 대해서 적용하지만
.excludePathPatterns("/","members/add","/login","/logout",
"/css/**","/*.ico","/error"); // 이경로들은 제외해라!
}
}
정리
- 서블릿 필터와 스프링 인터셉터는 웹과 관련된 공통 관심사를 해결하기 위한 기술
- 특별한 문제가 없다면 사용하기 편리한 인터셉터를 사용하는 것이 좋음
애너테이션을 만들어서 파라미터에 사용하려면 ArgumentResolver에서 인식하게 해야함
supportsParameter()
로 ArgumentResolver가 사용되는 조건에 대해 작성resolveArgument()
는 supportsParameter()
에서 true가 반환되면 실행되는 로직