인터셉터
서블릿 필터에 이어 웹과 관련된 공통 관심사를 해결할 수 있는 방법으로 스프링 MVC가 제공하는 인터셉터가 있다.
인터셉터는 컨트롤러 호출 직전에 호출이 되며 필터처럼 체인으로 구성이 되는 등 비슷한 부분이 많지만 필터에 비해 좀 더 편리하고 정교한 기능을 지원한다.
먼저, 인터셉터를 사용하려면. HandlerIntercepter 인터페이스를 구현해야 한다.
- preHandle : 컨트롤러 호출 전 동작
- postHandle : 컨트롤러 호출 후 동작, 컨트롤러 예외 발생 시 호출되지 않는다.
- afterCompletion : 마지막에 항상 호출, 예외를 받아서 처리할 수 있다.
DispatcherServlet -> preHandle -> handle() -> Controller -> postHandle -> render() -> View -> afterCompletion
public class LogInterceptor implements HandlerInterceptor {
public static final String LOG_ID = "logId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession(false);
//@Controller, @RequestMapping으로 핸들러 매핑을 할 경우, 핸들러 정보로 HandlerMethod가 넘어온다.
if (handler instanceof HandlerMethod) {
//호출할 컨트롤러 메서드의 모든 정보가 포함되어 있다.
HandlerMethod hm = (HandlerMethod) handler;
}
if (session == null || session.getAttribute("loginMember") == null) {
redirect response.sendRedirect("/login?redirectURL=" + requestURI);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
//ModelAndView를 받을 수 있다.
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// Exception을 받아서 처리하거나 넘길 수 있다.
}
}
인터셉터는 WebMvcConfigurer가 제공하는 addInterceptors() 를 사용해서 등록할 수 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1) // 필터와 마찬가지로 호출 우선 순위
.addPathPatterns("/**") // URL 패턴
.excludePathPatterns("/css/**", "/*.ico", "/error"); // 인터셉터 제외 패턴
// 2번째 인터셉터 등록
registry.addInterceptor(new LoginCheckInterceptor())
.order(2)
.addPathPatterns("/**")
.excludePathPatterns("/", "/members/add", "/login", "/logout",
"/css/**", "/*.ico", "/error");
}
}
필터보다 URL 패턴을 더욱 세밀하게 설정할 수 있다.
(https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/pattern/PathPattern.html)
ArgumentResolver를 활용한 로그인 회원 조회
직접 만든 ArgumentResolver를 추가해서 로그인 회원을 편리하게 조회할 수 있다.
ArgumentResolver는 핸들러 어댑터에서 핸들러(컨트롤러)를 호출할 때 컨트롤러의 파라미터, 애노테이션 정보를 기반으로 전달 데이터를 생성하는 역할을 한다.
(ArgumentResolver는 요청 값을 처리하고 응답 값을 변환하고 처리하는 것은 ReturnValueHandler가 한다.)
@Login 애노테이션을 새로 만들어서 컨트롤러 파라미터에 입력하고 직접 만든 ArgumentResolver에서 이를 이용할 수 있다.
//@GetMapping을 제거하고 @Login 애노테이션을 선언
//@GetMapping("/")
public String homeLogin(@Login Member loginMember, Model model) {
...
}
//@Login 애노테이션 생성
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {
}
스프링은 30개가 넘는 ArgumentResovler를 기본으로 제공하는데 여기에 직접 만든 ArgumentResolver를 추가할 수 있다.
HandlerMethodArgumentResolver의 supportsParameter()를 호출해서 해당 파라미터를 지원하는지 체크하고, 지원하면 resolveArgument()를 호출해서 실제 객체를 생성하고 컨트롤러 호출 시 전달할 수 있다.
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean hasLoginAnnotation = parameter.hasParameterAnnotation(Login.class);
boolean hasMemberType = Member.class.isAssignableFrom(parameter.getParameterType());
return hasLoginAnnotation && hasMemberType;
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
HttpSession session = request.getSession(false);
if (session == null) {
return null;
}
// 컨트롤러 파라미터에 선언된 @Login Member loginMember에 member 객체를 전달
return session.getAttribute("loginMember");
}
}
생성한 ArgumentResolver는 다음과 같이 등록할 수 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new LoginMemberArgumentResolver());
}
...
}
'Spring' 카테고리의 다른 글
[스프링 MVC2] API 예외 처리 (0) | 2022.06.17 |
---|---|
[스프링 MVC2] 예외 처리와 오류 페이지 (0) | 2022.06.17 |
[스프링 MVC2] 서블릿 필터 (0) | 2022.06.16 |
[스프링 MVC2] 쿠키와 세션 (0) | 2022.06.16 |
[스프링 MVC2] 애노테이션 검증 (Bean Validation) (0) | 2022.06.15 |