안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
Filter
- HTTP 요청과 응답 사이에서 전달되는 데이터를 가로채어 서비스에 맞게 변경하고 걸러내는 필터링 작업을 수행
- 요청한 URL을 기준으로 필터링 작업
- servlet이 실행되기 전에 먼저 수행 (전처리) / 후처리도 가능 (응답 메세지를 모두 작성하고 마지막에 client에게 보내기 전에 수행)
- filter는 여러개 존재 가능 → filter chain
filter 생성
filter package 생성 - Next
Filter mappings (어떤 URL에 filter 적용을 할 건지 적용) → *는 모든 URL을 의미
Filter의 생명주기
① 객체생성 (생성자 호출)
② init (필터객체 전처리)
③ doFilter (처리코드)
④ destroy (메모리 반환 전 처리)
/**
* Filter의 생명주기
* - 객체생성 (생성자 호출)
* - init (필터객체 전처리)
* - doFilter (처리코드)
* - destroy (메모리 반환 전 처리)
*/
@WebFilter("/*")
public class LogFilter implements Filter {
/**
* Default constructor.
*/
public LogFilter() {
System.out.println("[LogFilter 생성]");
}
/**
* @see Filter#destroy()
*/
public void destroy() {
System.out.println("[LogFilter destroy]");
}
/**
* 필터를 통해 처리할 코드 작성
* - 전처리
* - 후처리
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 전처리
// filter chain의 다음 filter를 호출 (마지막 필터라면 servlet 호출)
chain.doFilter(request, response);
// 후처리
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("[LogFilter init]");
}
}
위와 같이 클래스가 생성되었습니다.
실제 처리 코드를 작성하는 doFilter메소드를 자세히 확인해보도록 하겠습니다.
doFilter의 매개변수를 확인해보면 ServletRequest, ServletResponse인 것을 확인할 수 있습니다.
Servlet에서의 doGet, doPost메소드에서는 HttpServletRequest/Response 타입이였지만, Filter는 부모 인터페이스인 ServletRequest/Response 타입을 제어하고 있는 것을 알 수 있습니다.
즉, request/response에는 같은 객체가 넘어오지만 제어하고 있는 타입이 다르다는 것!! (다형성)
- FilterChain은 filte들을 관리하고 있는 객체 (다음 filter를 호출하기 위해 매개인자로 넘겨줌)
chain.doFilter(request, response) 로 filter chain상의 다음 filter를 호출하며, 마지막 필터라면 servlet을 호출합니다.
@WebFilter("/*")
public class LogFilter implements Filter {
/**
* Default constructor.
*/
public LogFilter() {
System.out.println("[LogFilter 생성]");
}
/**
* @see Filter#destroy()
*/
public void destroy() {
System.out.println("[LogFilter destroy]");
}
/**
* 필터를 통해 처리할 코드 작성
* - 전처리
* - 후처리
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 전처리
HttpServletRequest httpReq = (HttpServletRequest) request;
String uri = httpReq.getRequestURI();
String method = httpReq.getMethod();
System.out.println("==========================================");
System.out.printf("%s %s\n", method, uri);
System.out.println("------------------------------------------");
// filter chain의 다음 filter를 호출 (마지막 필터라면 servlet 호출)
chain.doFilter(request, response);
// 후처리
HttpServletResponse httpRes = (HttpServletResponse) response;
System.out.println(httpRes.getStatus());
System.out.println("------------------------------------------");
System.out.println();
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("[LogFilter init]");
}
}
@콘솔출력값
[LogFilter 생성]
[LogFilter init]
==========================================
GET /mvc2/
------------------------------------------
[sessionCreated] 현재 세션 수 : 1
200
------------------------------------------
==========================================
GET /mvc2/css/style.css
------------------------------------------
304
------------------------------------------
==========================================
POST /mvc2/member/login
------------------------------------------
[회원로그인] 홍길동님 로그인!
302
------------------------------------------
==========================================
GET /mvc2/
------------------------------------------
JSESSIONID = 164EBB6FDB46A44AE0E95785930D8DE5
200
------------------------------------------
[LogFilter destroy]
[회원로그아웃] 홍길동님 로그아웃!
getRequestURI, getMethod, getStatus는 HttpServletRequest객체에서 사용 가능하므로, 다운캐스팅을 해주었습니다.
중복되는 코드 filter로 처리하기
Controller단의 중복코드인 인코딩 처리를 filter로 해결!
@WebFilter("/*")
public class EncodingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String encodingType = "utf-8";
request.setCharacterEncoding(encodingType);
System.out.println("[EncodingFilter : " + encodingType + " 처리]");
chain.doFilter(request, response);
}
}
@콘솔출력값
[LogFilter 생성]
[LogFilter init]
[EncodingFilter : utf-8 처리]
==========================================
GET /mvc2/
------------------------------------------
JSESSIONID = 0B6E0F8C0B614BC5FF77F705D3CC4507
200
------------------------------------------
출력값을 보면 EncodingFilter가 먼저 처리되고, 위에서 생성했던 LogFilter가 처리되는 것을 확인할 수 있습니다.
어노테이션으로 작성한 Filter의 처리순서는 알파벳 순이므로, 순서를 지정하고자 한다면, web.xml에 등록해야합니다.
web.xml
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.ce.mvc2.common.filter.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.ce.mvc2.common.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
@콘솔출력값
[LogFilter 생성]
[LogFilter init]
==========================================
GET /mvc2/
------------------------------------------
[EncodingFilter : utf-8 처리]
JSESSIONID = 0B6E0F8C0B614BC5FF77F705D3CC4507
200
------------------------------------------
이번엔 LogFilter가 먼저 처리된 후 EncodingFilter가 처리되는 것을 확인할 수 있습니다.
(web.xml에 등록된 filter가 먼저 처리되고, 어노테이션으로 등록한 filter가 처리!)
web.xml에서 init 파라미터 작성하여 처리도 가능
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.ce.mvc2.common.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encodingType</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
public class EncodingFilter implements Filter {
private String encodingType;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// String encodingType = "utf-8";
request.setCharacterEncoding(encodingType);
System.out.println("[EncodingFilter : " + encodingType + " 처리]");
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
this.encodingType = fConfig.getInitParameter("encodingType");
}
}
@콘솔출력값
[LogFilter 생성]
[LogFilter init]
==========================================
GET /mvc2/
------------------------------------------
[EncodingFilter : utf-8 처리]
JSESSIONID = 0B6E0F8C0B614BC5FF77F705D3CC4507
200
------------------------------------------
접근권한을 Filter로 통제하기
로그인을 해야만 이용할 수 있는 페이지에 직접 URL을 작성하여 접근하였을 때를 대비하여 Filter로 처리해보겠습니다.
내정보보기(memberView)는 loginMember를 통해서 id, name 등 정보를 가져오지만, 현재 로그인이 되어있지 않은 상태에서 접근하였기 때문에 아래와 같은 NullPointerException이 발생하는 것을 확인할 수 있습니다.
LoginFilter
//@WebFilter(urlPatterns = { "/member/memberView", "/member/memberUpdate", "/member/memberDelete" })
//@WebFilter(value = { "/member/memberView", "/member/memberUpdate", "/member/memberDelete" })
@WebFilter({ "/member/memberView", "/member/memberUpdate", "/member/memberDelete" })
public class LoginFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpRes = (HttpServletResponse) response;
HttpSession session = httpReq.getSession();
Member loginMember = (Member) session.getAttribute("loginMember");
if(loginMember == null) {
session.setAttribute("msg", "로그인 후 이용 가능합니다.");
httpRes.sendRedirect(httpReq.getContextPath() + "/");
return;
}
chain.doFilter(request, response);
}
}
@WebFilter 어노테이션을 통해 적용할 URL을 지정해주었습니다.
(urlPatterns, value를 key값으로 갖지만 생략가능!)
index페이지로 redirect 처리하였으므로, memberView는 302, mvc2/는 200 상태인 것을 확인할 수 있습니다.
또한, return을 하여 servlet이 실행되지 않도록 하였습니다. (return 하지 않으면 안됨!)
'Java > Servlet & JSP' 카테고리의 다른 글
JSP) error page - exception 발생 예외/status 발생 예외 (0) | 2022.06.27 |
---|---|
JSP) 암호화 - salt 처리, 비밀번호 변경 페이지 생성 (0) | 2022.06.26 |
JSP) 회원가입 아이디 중복 검사 (0) | 2022.06.25 |
JSP) 예외 처리 (0) | 2022.06.24 |
JSP) 회원가입 처리하기 (0) | 2022.06.23 |