프로필사진
RESTful(10) - filter, interceptor

2020. 7. 8. 21:49🔴 Spring

300x250

사용목적 = 공통적으로 처리할 업무 진행

권한 체크, 로그인 관리, 페이지 인코딩 등의 업무를 공통적으로 여러 곳에서 처리해야 하는 상황이라면,
같은 코드를 중복해서 사용하기보다는 공통 프로세스로 떼어내어 따로 개발하는 게 더 효율적이다.

이미지 출처 : https://goddaehee.tistory.com/154

filter와 interceptor 모두 '공통'적으로 어떠한 로직을 수행하는것인데,
실행 흐름을 보면 (1) filter - (2) interceptor 이렇게 있다.
따라서 요청이 들어오면 가장 먼저 거치는 부분은 filter, 그다음엔 interceptor이다.


Filter

- 요청&응답 거른 뒤 정제하는 역할
- 스프링 콘텍스트 외부에 존재 -> 스트링과 무관한 자원에 대해 동작함
- 앞단에서 요청 내용을 변경하거나 체크할 수 있음
- 자원처리가 끝난 후, 응답 내용을 변경할 수 있음
- web.xml에 등록
- init(), doFilter(), destroy()
- 사용 예시 ) 인코딩 변환, XSS방어

예시 1 (로그인 체크) :

<web.xml>

<!-- web.xml에서 매핑하든가 클래스 내부에서 annotation으로 적용하든가 -->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>filter.CharacterEncodingFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

<LoginCheckFilter.java>

package filter;


import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebFilter({ "/LoginCheckFilter", "/mypage/*" })
public class LoginCheckFilter implements Filter {


    public LoginCheckFilter() {
        // TODO Auto-generated constructor stub
    }


	public void destroy() {
		// TODO Auto-generated method stub
	}


	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

		HttpServletRequest req = (HttpServletRequest)request;
		
		HttpServletResponse resp = (HttpServletResponse)response;
		
		//로그인 정보 -> session에 저장되어있음
		//Parameters:create - true to create a new session for this request if necessary; false to return null if there's no current session
		//Returns:the HttpSession associated with this request or null if create is false and the request has no valid session
		HttpSession session = req.getSession(false);
		
		boolean loginchk = false;
		
		// 1. 로그인 되어있는지 확인 -> 되어있으면 true
		if(session != null && session.getAttribute("LoginInfo") != null) {
			loginchk = true;
		}
		
		// 2. 로그인 되어있는지에 따라 다른 처리
		if(loginchk) {
			// 로그인 OOO -> chain => 등록한 다른 필터에 변경된 요청사항들을 보냄
			chain.doFilter(request, response);
			
		} else {
			// 로그인 XXX -> redirect
			resp.sendRedirect(req.getContextPath()+"/session/member/loginForm.jsp");
//			RequestDispatcher dispatcher = request.getRequestDispatcher("/session/member/loginForm.jsp");
//			dispatcher.forward(request, response);
			
		}
		
		
		
	}

	public void init(FilterConfig fConfig) throws ServletException {
		// TODO Auto-generated method stub
	}

}

 

예시 2 (인코딩) :

<CharactorEncodingFilter.java>

package filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

// 이부분 주석처리하면 실행 안됨
//@WebFilter(
//		urlPatterns = { "/*" }, 
//		initParams = { 
//				@WebInitParam(name = "encoding", value = "UTF-8")
//		})
public class CharacterEncodingFilter implements Filter {

	private String encoding;

	public CharacterEncodingFilter() {
		// TODO Auto-generated constructor stub
	}

	public void destroy() {
		// TODO Auto-generated method stub
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		// encoding 적용하기
		request.setCharacterEncoding(encoding);

		// 다른 필터에 체인처럼 연결
		chain.doFilter(request, response);
	}

	public void init(FilterConfig fConfig) throws ServletException {
		encoding = fConfig.getInitParameter("encoding");
		if (encoding == null) {
			encoding = "UTF-8";
		}

	}

}

Interceptor

- 컨트롤러에 들어오는 요청(HttpRequest)과 응답(HttpResponse)을 가로채는 역할
- DispatcherServlet이 컨트롤을 호출하기 전/후에 끼어듦 -> 스프링 콘텍스트 내부에서 컨트롤러에 관한 요청, 응답 처리함
- 모든 bean 객체에 접근 가능
- 여러 개 사용 가능
- preHandler(), postHandler(), afterCompletion()
- 사용 예시 ) 로그인 체크, 권한 체크, 로그 확인


Filter & Interceptor 차이점

1. 호출 시점
Filter는 DispatcherServlet이 실행되기 전 , Interceptor는 DispatcherServlet이 실행된 후

2. 설정 위치
Filter는 web.xml , Interceptor는 spring-servlet.xml

3. 구현 방식
Filter는 web.xml에서 설정을 하면 구현이 가능하지만, Interceptor는 설정은 물론 메서드 구현이 필요하다.


참고: 

https://victorydntmd.tistory.com/176

https://goddaehee.tistory.com/154

300x250