Servlet Filter & Wrapper
목표: 공통 로직(인코딩/보안/로깅 등)을 Filter로, 요청/응답 객체를 변형해야 하면 Wrapper로.
1) Servlet Filter
1-1) 정의 & 역할
javax.servlet.Filter 구현 클래스.
- 요청/응답을 서블릿 전·후로 가로채서 가공(보안, 인코딩, 로깅, 압축, 리소스 접근 제어 등).
- 여러 개를 체인(FilterChain) 으로 연결 가능 → 앞에서 뒤로, 돌아오며 역순 실행.
1-2) 동작 구조
- 클라이언트 → Filter 1 → Filter 2 → … → Servlet(service/doGet/doPost) → … → Filter 2 → Filter 1 → 클라이언트
- 마지막 필터에서
chain.doFilter(req, res) 호출해야 다음 단계로 진행.
1-3) 생명주기 메서드
void init(FilterConfig config)
void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
void destroy()
1-4) 설정 방법
(A) web.xml
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.example.EncodingFilter</filter-class>
<init-param>
<param-name>encoding-type</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-name 매핑도 가능.
(B) 어노테이션
import jakarta.servlet.annotation.WebFilter;
@WebFilter("/*")
public class EncodingFilter implements Filter { ... }
1-5) 예시: POST 인코딩 공통 처리
public class EncodingFilter implements Filter {
private String encoding;
@Override
public void init(FilterConfig cfg) {
encoding = cfg.getInitParameter("encoding-type");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
if (req instanceof HttpServletRequest http && "POST".equals(http.getMethod())) {
req.setCharacterEncoding(encoding);
}
chain.doFilter(req, res);
}
}
2) Servlet Wrapper
2-1) 정의
- 요청/응답 객체를 데코레이션하는 래퍼:
HttpServletRequestWrapper, HttpServletResponseWrapper.
- 원본을 감싸 특정 메서드만 선택적으로 재정의 → 파라미터 조작/마스킹/암호화, 응답 가공 등.
2-2) 주요 클래스
public class RequestWrapper extends HttpServletRequestWrapper {
public RequestWrapper(HttpServletRequest request) { super(request); }
@Override
public String getParameter(String name) {
if ("password".equals(name)) {
var raw = super.getParameter(name);
return new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder()
.encode(raw);
}
return super.getParameter(name);
}
}
@WebFilter("/member/*")
public class PasswordEncryptFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest http = (HttpServletRequest) req;
chain.doFilter(new RequestWrapper(http), res);
}
}
- 컨트롤러/서블릿에서는 평문이 아닌 해시 문자열을 받게 됨. 검증 시:
BCryptPasswordEncoder enc = new BCryptPasswordEncoder();
enc.matches("plainPassword", hashedFromDb);
2-3) 언제 쓰나?
- Filter: “모든 요청에 공통으로” 적용(인코딩, 인증/인가, 로깅, 압축…)
- Wrapper: “요청/응답 객체의 동작을 바꿔야” 할 때(파라미터 위장/마스킹, 출력 변환 등)
3) 실전 팁
doFilter()에서 chain.doFilter()를 반드시 호출(차단 목적이 아니라면).
- 여러 필터 사용 시 순서를 고려(web.xml 등록 순서, 또는 프레임워크 제공 우선순위).
- 인코딩은 POST 본문 파싱 전에 설정해야 효과 있음.
- 보안 데이터(패스워드)는 단방향 해시(BCrypt) 를 표준으로.
dispatcher 옵션으로 FORWARD/ERROR 시에도 필터 적용 제어.
핵심 요약
- Filter = 공통로직(인코딩/보안/로깅) 적용 지점, 서블릿 전·후로 가로채 가공
- Wrapper = 요청/응답 객체의 메서드 오버라이드로 동작 변경
- 설정은 web.xml 또는
@WebFilter, url-pattern 매핑이 우선
doFilter() 내 chain.doFilter() 호출 잊지 않기
- 민감정보는 BCrypt 해시 + matches 검증, 평문 저장 금지