Spring Interceptor
웹 사이트를 만들다보면 여러페이지에서 동일한 설정, 또는 검사를 반복해야하는 경우가 있다.
그럴경우, 필터나 인터셉터로 처리할 수 있다.
Filter는 요청과 응답을 정제하는 역할을 한다.
web.xml 또는 application.properties에서 설정하고 보통 인코딩 처리를 한다.
Filter는 DispatcherServlet 이전, DispatcherServlet이 응답을 반환 후에 실행하기 때문에
Filter를 통해 자원의 처리 이전 요청 내용을 변경하거나 자원을 처리한 후 응답을 변경할 수 있다.
init(): 필터 인스턴스 초기화
doFilter(): 필터 전/후 처리
destroy(): 필터 인스턴스 종료
web.xml 에서 UTF-8 인코딩
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
url-pattern을 /*로 설정하면 servlet, jsp, img 등 모든 자원에 적용된다.
application.properties에서 인코딩 필터 설정하기
하지만 자원의 처리과정 중 필요한 처리는 수행하지 못한다.
그럴때 Interceptor를 사용한다.
Interceptor는 DispatcherServlet이 HandlerMapping 직후 Controller을 호출하기 직전, 직후, View를 Rendering한 후 실행된다.
Interceptor는 여러개 사용할 수 있고, Controller에서 요청을 처리하기 전 로그인 체크, 권한 체크, 처리 한 후 실행 시간 계산과 같은 작업을 수행할 수 있다.
preHandle(): Controller 요청 처리 전
postHandle(): Controller 요청 처리 후
afterCompletion(): View Rendering 후
Interceptor 만들기
-HandlerInterceptor 인터페이스를 상속받아 메소드를 구현한다.
public class AuthLoginInterceptor implements HandlerInterceptor {
public AuthLoginInterceptor() {
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/***********************************************************************************
1. handler객체 종류 확인
우리가 관심 있는 것은 @Controller객체에 있는 매핑된(@RequestMapping이 붙은) 메서드이므로
HandlerMethod 타입인지 체크
*************************************************************************************/
if (handler instanceof HandlerMethod == false) {
/*
* @ Controller객체에 @RequestMapping이 붙은메쏘드 : HandlerMethod
*/
//return true이면 그대로 컨트롤러로 진행
return true;
}
HttpSession session = request.getSession();
String sUserId = (String) session.getAttribute("sUserId");
if (sUserId == null) {
response.sendRedirect("user_main");
return false;
}
return true;
}
}
로그인 상태 확인을 위한 Interceptor로 Controller 호출 전 Interceptor에서 로그인 상태를 확인하고
로그인이 되어 있을 때만 Controller를 호출할 수 있게 한다.
반환 값은 boolean 타입으로 true면 Mapping된 Controller를 호출하고 false면 Controller로 가지 않고 실행을 멈춘다.
위 코드에서는 로그인이 되어있지 않은 상태면 main페이지로 redirect 했는데
Interceptor는 Controller가 아니기 때문에 redirectPath를 반환하거나 main Controller uri로 보낼 수 없고
파라메터로 받은 response로 직접 redirect한다. response.sendRedirect();
preHandle메소드를 보면 Object handler 객체를 받는다.
handler객체는 @requestMapping이 된 메소드의 정보(컨트롤러, 메타정보, 파라메터, 어노테이션 메타정보, 리턴 값 메타정보..)를 가지고 있는 HandlerMethod객체이다.
if (handler instanceof HandlerMethod == false) {
// @ Controller객체에 @RequestMapping이 붙은메쏘드 : HandlerMethod
//return true이면 그대로 컨트롤러로 진행
return true;
}
handler가 mapping된 handlerMethod인지 확인하는 작업으로
맵핑이 안된 메소드면 바로 Controller로 이동
이후 필요한 작업(로그인 확인 처리)를 하면 된다.
Annotation을 이용한 Interceptor를 만들 때는
HandlerMethod를 확인하고 HandlerMethod객체의 어노테이션 메타 정보를 가져와 확인하는 작업을 추가한 후 필요한 작업을 하면 된다.
//2.HandlerMethod 타입으로 형 변환
HandlerMethod handlerMethod = (HandlerMethod) handler;
//3.HandlerMethod객체 로부터 @LoginCheck 어노테이션 객체얻기
LoginCheck loginCheck = handlerMethod.getMethodAnnotation(LoginCheck.class);
//4. HandlerMethod객체에 @LoginCheck어노테이션 이없는 경우,
즉 인증이 필요 없는 요청
if (loginCheck == null) return true;
//4. HandlerMethod객체에 @LoginCheck어노테이션 이있는 경우, 로그인 체크...
Interceptor를 구현한 후
WebConfig나 mvc-config.xml 에 Interceptor를 등록한다.
Annotation을 사용하지 않는 경우
@Override
public void addInterceptors(InterceptorRegistry registry) {
AuthLoginInterceptor authLoginInterceptor=new AuthLoginInterceptor();
registry.addInterceptor(authLoginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/css/**")
.excludePathPatterns("/js/**")
.excludePathPatterns("/image/**")
.excludePathPatterns("/user_main")
}
addInterceptors 메소드에서 registry에 Interceptor를 추가하고 pathPattern을 추가하거나 제외한다.
@Override
public void addInterceptors(InterceptorRegistry registry) {
AuthLoginAnnotationInterceptor authLoginAnnotationInterceptor=
new AuthLoginAnnotationInterceptor();
registry.addInterceptor(authLoginAnnotationInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/css/**")
.excludePathPatterns("/js/**")
.excludePathPatterns("/image/**");
}
Annotation을 사용하는 경우
Interceptor를 Annotation을 적용한 Interceptor를 추가한다.
mvc-config.xml파일에서 설정할 경우
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itwill.user.controller.AuthLoginAnnotationInterceptor" />
</mvc:interceptor>
</mvc:interceptors>