서블릿 필터 (Servlet Filter)
서블릿 필터는 웹 애플리케이션에서 클라이언트의 요청(Request)과 서버의 응답(Response)을 중간에서 가로채서 처리하는 재사용 가능한 코드 컴포넌트이다. 필터를 사용하면 요청 처리 전/후에 공통적인 로직(보안, 로깅, 데이터 변환 등)을 중앙 집중화하여 효율적으로 관리할 수 있다.
주요 특징 및 역할
- 요청/응답 가로채기: 클라이언트의 요청이 서블릿/JSP 등 웹 리소스에 도달하기 전, 또는 응답이 클라이언트로 전송되기 전에 필터가 동작.
- 체인(Chain) 형태의 동작: 여러 개의 필터를 연결하여 순차적으로 처리할 수 있다. (필터 체인)
- 재사용성: 필터는 한 번 작성하여 여러 서블릿/JSP에 적용할 수 있다.
- 선언적 구성: web.xml (Deployment Descriptor) 또는 애노테이션(@WebFilter)을 사용하여 필터를 설정하고 매핑할 수 있다.
필터의 동작 방식
- 요청 필터링:
- 클라이언트가 웹 리소스(서블릿, JSP 등)를 요청.
- 요청이 웹 컨테이너(서블릿 컨테이너)에 도착.
- 웹 컨테이너는 요청 URL과 매핑된 필터 체인을 확인.
- 필터 체인에 있는 각 필터의 doFilter() 메서드가 순차적으로 호출.
- doFilter() 메서드 내에서 요청을 처리하거나, 다음 필터로 요청을 전달.(chain.doFilter(request, response);)
- 필터는 요청을 변경하거나, 특정 조건에 따라 요청을 중단하고 응답을 보낼 수도 있다.
- 마지막 필터가 doFilter()를 호출하면, 요청은 원래 요청된 웹 리소스(서블릿, JSP)로 전달.
- 응답 필터링:
- 웹 리소스(서블릿, JSP)가 응답을 생성.
- 응답은 필터 체인을 역순으로 통과. (요청 필터링 순서와 반대)
- 각 필터의 doFilter() 메서드 내에서 응답을 처리하거나, 이전 필터로 응답을 전달.
- 필터는 응답 내용을 수정하거나, 추가적인 작업을 수행할 수 있다.
- 최종 응답은 클라이언트로 전송.
Filter 인터페이스
서블릿 필터를 구현하려면 javax.servlet.Filter 인터페이스를 구현해야 한다. 이 인터페이스는 다음 세 가지 메서드를 정의.
- init(FilterConfig config): 필터 초기화 시 호출됩니다. FilterConfig 객체를 통해 필터 설정 정보에 접근할 수 있다. (한 번만 호출)
- doFilter(ServletRequest request, ServletResponse response, FilterChain chain): 실제 필터링 로직을 구현하는 메서드. FilterChain 객체를 사용하여 다음 필터로 요청/응답을 전달. (요청/응답마다 호출)
- destroy(): 필터가 제거될 때 호출. (한 번만 호출)
활용 예시
- 인증 및 권한 관리: 로그인 여부 확인, 사용자 권한 검사 등
- 로깅: 요청/응답 정보 기록, 에러 로깅 등
- 데이터 압축/암호화: 응답 데이터 압축, 요청/응답 데이터 암호화/복호화
- 캐싱: 정적 리소스 캐싱
- XSS(Cross-Site Scripting) 방지: 입력 데이터 검증 및 필터링
- 문자 인코딩 변환: 요청/응답 문자 인코딩 설정
- HTTP 헤더 추가/수정: 요청/응답 헤더 조작
필터 설정 방법
web.xml (Deployment Descriptor):
XML
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern> </filter-mapping>
애노테이션 (@WebFilter): (Servlet 3.0 이상)
Java
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*") // 또는 @WebFilter(urlPatterns = {"/*"}, servletNames = {"MyServlet"})
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 초기화 로직
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 필터링 로직 (요청 처리 전)
chain.doFilter(request, response); // 다음 필터 또는 서블릿으로 요청 전달
// 필터링 로직 (응답 처리 후)
}
@Override
public void destroy() {
// 필터 제거 시 로직
}
}
장점
- 코드 중복 감소: 공통 로직을 필터에 모아 코드 중복을 줄이고 유지보수를 용이하게 한다.
- 관심사 분리 (Separation of Concerns): 핵심 비즈니스 로직(서블릿/JSP)과 부가적인 기능(필터)을 분리하여 코드 가독성과 재사용성을 높인다.
- 유연성: 필터 체인을 통해 필터 적용 순서를 쉽게 변경하고, 새로운 필터를 추가/제거할 수 있다.
'개발 > servlet' 카테고리의 다른 글
리소스에 접근하는 방법 (0) | 2025.03.14 |
---|---|
리스너(Listener) (0) | 2025.03.13 |
PRG(Post-Redirect-Get) 패턴 (0) | 2025.03.05 |
MVC 패턴 (0) | 2025.03.05 |
HttpSession 과 Cookie 인터페이스 정리 (0) | 2025.03.05 |