
Request FilterResponse FilterFilter Chainpublic interface Filter {
void init(FilterConfig config) throws ServletException;
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
void destroy();
}
init(FilterConfig config)<filter> 의 <init-parm> 값이 여기로 들어온다.doFilter(request, response, chain)chain.doFilter(request, response)를 기준으로 destroy()<filter>
<filter-name>encoding</filter-name>
<filter-class>com.section02.uses.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>
<filter-mapping>
<filter-name>encoding</filter-name>
<servlet-name>loginServlet</servlet-name>
</filter-mapping>
url-pattern 매핑과 servlet-name 매핑 모두 가능url-pattern이 우선XML 대신 클래스 위에 직접 선언하는 방식
@WebFilter("/first/*")
public class FirstFilter implements Filter {
// 필터 구현
}
/first/로 시작하는 모든 요청에 이 필터 적용@WebFilter("/first/*")
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("FirstFilter init호출");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("Filter doFilter 메소드 호출"); // 서블릿 전
chain.doFilter(request, response); // 다음 필터 또는 서블릿 호출
System.out.println("서블릿 요청 수행 완료"); // 서블릿 후
}
@Override
public void destroy() {
System.out.println("Filter destroy 메소드호출");
}
}
@WebServlet("/first/filter")
public class FirstFilterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Servlet doGet메소드 호출");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h1>필터 확인용 서블릿</h1>");
out.close();
}
}
브라우저에서 /first/filter 요청 시:
FirstFilter init호출
Filter doFilter 메소드 호출
Servlet doGet메소드 호출
서블릿 요청 수행 완료
Filter destroy 메소드호출
이 예제는 필터가 서블릿 앞뒤에서 어떻게 흐름을 잡는지를 보여주는 기본 템플릿이라고 보면 된다.
public class EncodingFilter implements Filter {
private String encodingType;
@Override
public void init(FilterConfig fConfig) throws ServletException {
encodingType = fConfig.getInitParameter("encoding-type");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest) request;
if ("POST".equals(hrequest.getMethod())) {
request.setCharacterEncoding(encodingType);
}
chain.doFilter(request, response);
}
@Override
public void destroy() { }
}
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.section02.uses.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>
HttpServletRequestWrapper, HttpServletResponseWrapper 는 기존 요청/응답 객체를 감싸서 기능을 추가하는 일종의 “장식(Decorator)” 클래스public class SampleRequestWrapper extends HttpServletRequestWrapper {
public SampleRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
// 여기서 파라미터를 가공해서 반환 가능
return super.getParameter(name);
}
}
public class RequestWrapper extends HttpServletRequestWrapper {
public RequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = "";
if ("password".equals(name)) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
value = encoder.encode(super.getParameter(name));
System.out.println("value = " + value);
} else {
value = super.getParameter(name);
}
return value;
}
}
password 파라미터를 읽을 때BCryptPasswordEncoder로 암호화된 값 반환userId, name 등)는 그대로 반환즉,
원래: request.getParameter("password") → "12345678"
Wrapper 적용 후: request.getParameter("password") → "$2a$10$..."
@WebFilter("/member/*")
public class PasswordEncryptFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest) request;
RequestWrapper wrapper = new RequestWrapper(hrequest);
chain.doFilter(wrapper, response);
}
@Override
public void init(FilterConfig fConfig) throws ServletException { }
@Override
public void destroy() { }
}
/member/* 로 들어오는 모든 요청은 이 필터를 먼저 거침HttpServletRequest를 RequestWrapper로 감싸서 넘김request.getParameter("password")를 부르면@WebServlet("/member/regist")
public class RegistMemberServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userId = request.getParameter("userId");
String password = request.getParameter("password"); // 이미 암호화된 값
String name = request.getParameter("name");
System.out.println("userId = " + userId);
System.out.println("password = " + password);
System.out.println("name = " + name);
// 회원가입 시에는 여기에서 암호화된 password를 DB에 저장하는 역할을 해야 함
}
}
PasswordEncryptFilter → RequestWrapper를 거치면서 비밀번호가 BCrypt로 암호화됨matches(평문, 암호문) 으로 검증한다RequestWrapper)에서 비밀번호를 BCrypt로 암호화$2a$10$...)을 받는다// 결과적으로 서블릿에서는 이미 암호화된 상태로 받음
String encryptedPwd = request.getParameter("password");
memberDao.insert(userId, encryptedPwd, name);
로그인할 때는 암호화를 다시 하면 안 된다.
필터에서 암호화를 거치지 않거나, 로그인 요청만 예외 처리해야 한다.
BCryptPasswordEncoder.matches(입력 평문, DB 암호문) 으로 비교BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String inputPwd = request.getParameter("password"); // 평문
String dbPwd = member.getPassword(); // 암호문
boolean isMatch = encoder.matches(inputPwd, dbPwd);
init, doFilter, destroy 세 개의 메서드를 가진다.chain.doFilter(request, response) 이전은 전처리, 이후는 후처리 구간이다.web.xml의 <filter>, <filter-mapping> 또는 @WebFilter로 할 수 있다.UTF-8 인코딩을 적용하는 예제이다.HttpServletRequestWrapper)는 요청 객체를 감싸 기능을 확장하는 클래스이다.getParameter("password")를 오버라이드 하면 비밀번호 자동 암호화가 가능하다.matches(평문, 암호문)으로만 비교한다.이 정도를 머릿속에 흐름대로 그려두고,
FirstFilter → EncodingFilter → RequestWrapper + PasswordEncryptFilter → RegistMemberServlet 순서대로 코드를 한 번씩 직접 타이핑해 보면 필터와 래퍼 개념이 거의 정리될 것이다.