10장. 서블릿의 필터와 리스너 기능
10.1 서블릿 속성과 스코프
<서블릿 속성>
: 세가지 서블릿 API 클래스 HttpServletRequest, ServletContext, HttpSession에 저장되는 객체(정보)
=> 세개 모두 ~Attribute()로 바인딩된 속성을 조작
<서블릿 스코프>
: 바인딩된 속성에 대한 접근 범위
- HttpServletRequest =>리퀘스트 스코프(해당 요청/응답 에서만 접근 가능)
- ServletContext => 애플리케이션 스코프(애플리케이션 전체 접근 가능)
- HttpSession => 세션 스코프(브라우저에서만 접근 가능)
* 기능 : 로그인 상태 유지 기능, 장바구니 기능, MVC의 Model과 View의 데이터 전달 기능
10.2 서블릿의 여러 가지 URL 패턴
URL 패턴 : 서블릿의 매핑 이름, 반드시 /로 시작해야 함
URL 패턴 유형(우선순위 대로)
1) 정확히 일치 : ex. /first/test
2) 디렉터리만 일치 : ex. /first/*
3) 확장자만 일치 : ex. *.do
4) /* : 모든 요청 URL 패턴
getRequestURI, getRequestURL, getContextPath, getServletPath
10.3 Filter API
필터 : 요청 직후/응답 직전에 미리 여러가지 작업을 처리하는 기능
- 클라이언트-필터-서블릿
- 반복되는 작업을 필터에서 처리하면 편함(ex. 한글 인코딩)
용도에 따라 요청필터와 응답 필터가 있음(chain.doFilter() 전후로 나뉨)
- 요청 필터에서 주로 처리 : 사용자 인증 및 권한 검사 / 요청 관련 로그 작업 / 인코딩
- 응답 필터에서 주로 처리 : 응답 결과에 대한 암호화 작업 / 서비스 시간 측정
필터 관련 API
: Filter, FilterChain, FilterConfig
<Filter 인터페이스에 선언된 메서드>
- init() : 필터 생성 시 컨테이너에 의해 호출, 초기화 작업
- doFilter() : 요청/응답 시
- destroy() : 필터 소멸 시, 종료작업 수행
<FilterConfig의 메서드>
- getFilterName() : 필터 이름 반환
- getInitParameter(String name) : name에 대한 값 반환
- getServletContext() : 서블릿 컨텍스트 객체를 반환
<사용자 정의 Filter>
- 반드시 Filter 인터페이스를 구현
- 추상메서드 init(), doFilter(), destroy() 을 구현해줘야 함
- 필터 매핑 해줘야 함(@WebFilter("/*") )
New>Filter에서 필터 생성
chain.doFilter() 위쪽에 위치한 코드는 요청 필터, 아래에 위치한 코드는 응답 필터 기능 수행
@WebFilter("/*")
public class EncoderFilter implements Filter {
ServletContext context;
public void destroy() {
System.out.println("destroy() 호출");
}
//브라우저에서 요청하면 호출
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
System.out.println("Context 정보 : "+((HttpServletRequest)request).getContextPath()+
"\n URI 정보 : "+((HttpServletRequest)request).getRequestURI()+"\n 물리적 경로 : "
+request.getRealPath(((HttpServletRequest)request).getRequestURI()));
long begin=System.currentTimeMillis();
chain.doFilter(request, response); //다음 필터로 넘김. 밑에 코드는 응답 하면서 실행
long end=System.currentTimeMillis();
System.out.println("작업 시간 : "+(end-begin)+"ms");
}
//브라우저에 주소 입력하면 호출
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("init() 호출");
context=fConfig.getServletContext();
}
}
10.4 여러 가지 서블릿 관련 Listener API
서블릿 Listener : 서블릿에서 발생하는 이벤트에 대해 적절한 처리를 해줌
서블릿 관련 LIstener | 추상 메서드 | 기능 |
ServletContextListener |
|
Context 객체의 생성/소멸 이벤트 발생 시 처리한다. |
ServletContextAttributeListener |
|
Context 객체에 속성 추가/제거/수정 이벤트 발생 시 처리한다. |
HttpSessionListener |
|
Session 객체의 생성/소멸 이벤트 발생 시 처리한다. |
HttpSessionAttributeListener |
|
Session 객체에 속성 추가/제거/수정 이벤트 발생 시 처리한다. |
HttpSessionActivationListener |
|
세션의 활성화/비활성화 이벤트 발생 시 처리한다. |
HttpSessionBindingListener |
|
* 세션에 바인딩/언바인딩된 객체를 알려 주는 이벤트 발생 시 처리한다. * 리스너 중 유일하게 핸들러에 @WebListener 등록하지 않아도 된다. |
ServletRequestListener |
|
클라이언트의 Request 이벤트 발생 시 처리한다. |
ServletRequestAttributeListener |
|
Request 객체에 속성 추가/제거/수정 이벤트 발생 시 처리한다. |
HttpSessionBindingListener 이용해 로그인 접속자수 표시
LoginTest 서블릿
HttpSession session=request.getSession();
String user_id=request.getParameter("user_id");
String user_pw=request.getParameter("user_pw");
LoginImpl loginUser=new LoginImpl(user_id,user_pw);
if(session.isNew()) {
session.setAttribute("loginUser", loginUser); //loginImpl의 valueBound메서드 호출
}
String data="안녕하세요! <br> 로그인하셨습니다<br><br>";
data+="<head><script type='text/javascript'> setTimeout('history.go(0);',5000)</script></head>"; //history.go(0)==새로고침, setTimeout(코드,시간)
data+="<html><body>";
data+="아이디 : "+loginUser.user_id;
data+="<br>총 접속자수 : "+LoginImpl.total_user;
data+="</html></body>";
out.print(data);
LoginImpl > 리스너 구현하는 클래스(이벤트 핸들러)
public class LoginImpl implements HttpSessionBindingListener {
//loginImpl 객체 자체를 바인딩/언바인딩 해야 이벤트 발생하는 것임
String user_id;
String user_pw;
static int total_user=0;
public LoginImpl(String user_id, String user_pw) {
this.user_id = user_id;
this.user_pw = user_pw;
}
@Override
public void valueBound(HttpSessionBindingEvent event) { //세션에 바인딩 시 메서드 호출됨
System.out.println("사용자 접속");
++total_user;
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) { //세션에 소멸 시 메서드 호출 됨
System.out.println("사용자 접속 해제");
total_user--;
}
HttpSessionListener 이용해 로그인 접속자수&모든 로그인ID 표시하고 로그아웃 구현
- 세션 생성
- 컨텍스트에 사용자 아이디 저장
- 로그아웃 구현 : 세션 소멸시키기 이벤트
** HttpSessionListener에서는 기본 생성자를 꼭 만들어야 함에 주의
- loginImpl
@WebListener //세션바인딩 이벤트 제외 모두 달아줘야 함
public class LoginImpl implements HttpSessionListener {
String user_id;
String user_pw;
static int total_user=0;
public LoginImpl() { //생성필수
}
public LoginImpl(String user_id, String user_pw) {
this.user_id = user_id;
this.user_pw = user_pw;
}
public void sessionCreated(HttpSessionEvent se) { //세션 생성 시 이벤트
System.out.println("세션 생성");
++total_user;
}
public void sessionDestroyed(HttpSessionEvent se) { //세션 소멸 시 이벤트
System.out.println("세션 소멸");
total_user--;
}
}
- loginTest
@WebServlet("/login")
public class LoginTest extends HttpServlet {
List user_list=new ArrayList(); //do메서드에 넣지 않는다
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request,response);
}
protected void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
HttpSession session=request.getSession();
ServletContext ctx=getServletContext();
String user_id=request.getParameter("user_id");
String user_pw=request.getParameter("user_pw");
LoginImpl loginUser=new LoginImpl(user_id,user_pw);
if(session.isNew()) {
user_list.add(user_id);
ctx.setAttribute("user_list", user_list);
}
String data="안녕하세요! <br> 로그인하셨습니다<br><br>";
data+="<html><body>";
data+="아이디 : "+loginUser.user_id;
data+="<br>총 접속자수 : "+LoginImpl.total_user;
data+="<br>접속 아이디 : <br>";
List list=(ArrayList)ctx.getAttribute("user_list");
for(int i=0;i<list.size();i++)
{
data+=list.get(i)+"<br>";
}
data+="<a href='logout?user_id="+user_id+"'>로그아웃</a></html></body>";
out.print(data);
}
}
-logoutTest
@WebServlet("/logout")
public class LogoutTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
HttpSession session=request.getSession();
ServletContext ctx=getServletContext();
String user_id=request.getParameter("user_id");
session.invalidate();
List list=(List) ctx.getAttribute("user_list");
ctx.removeAttribute("user_list");
list.remove(user_id);
ctx.setAttribute("user_list", list);
String data="로그아웃했습니다<br><br>";
out.print(data);
}
}