setAttribute( )를 이용해 loginUser를 세션에 바인딩하면 LoginImpl 클래스에 구현된 이벤트 핸들러를 이용해 접속자수를 1 증가시키고, user_list에 접속자 ID를 저장한 다음 ServletContext 객체에 바인딩한다.
// LoginTest3.java
package sec04.ex02;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LoginTest2
*/
@WebServlet("/login")
public class LoginTest3 extends HttpServlet {
ServletContext context=null;
List user_list=new ArrayList(); // 로그인한 접속자 ID를 저장하는 ArrayList
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
context=getServletContext();
PrintWriter out = response.getWriter();
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); // LoginImpl 객체 생성 후 전송된 ID와 비밀번호 저장
// 최초 로그인 시 접속자 ID를 ArrayList에 차례로 저장한 후 다시 context 객체에 속성으로 저장
if(session.isNew()) {
session.setAttribute("loginUser", loginUser);
user_list.add(user_id);
context.setAttribute("user_list", user_list);
}
out.println("<html><body>");
out.println("아이디는 " + loginUser.user_id + "<br>");
out.println("총 접속자수는 " + LoginImpl.total_user + "<br><br>"); // 세션에 바인딩 이벤트 처리 후 총 접속자수를 표시
out.println("접속 아이디:<br>");
List list=(ArrayList)context.getAttribute("user_list"); // context 객체에 ArrayList를 가져와 접속자 ID를 차례로 브라우저에 출력
for(int i=0; i<list.size(); i++) {
out.println(list.get(i)+"<br>");
}
out.println("<a href='logout?user_id="+user_id+"'>로그아웃 </a>"); // 로그아웃 클릭 시 서블릿 logout으로 접속자 ID를 전송해 로그아웃
out.println("</body></html>");
}
}
// LoginImpl.java
package sec04.ex01;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class LoginImpl implements HttpSessionBindingListener {
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 valueBound(HttpSessionBindingEvent arg0) {
System.out.println("사용자 접속");
++total_user;
}
public void valueUnbound(HttpSessionBindingEvent arg0) {
System.out.println("사용자 접속 해제");
total_user--;
}
}
로그아웃 링크를 클릭하면 접속자 수를 1 감소시키고 user_list에서 로그아웃한 접속자 ID를 삭제한 후 다시 user_list를 ServletContext 객체에 바인딩하도록 설정한다.
// LogoutTest.java
package sec04.ex02;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LogoutTest
*/
@WebServlet("/logout")
public class LogoutTest extends HttpServlet {
ServletContext context;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
context=getServletContext();
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
String user_id = request.getParameter("user_id"); // user_list에서 삭제할 ID를 가져옴
session.invalidate(); // 로그아웃 시 세션을 소멸 시킴
// user_list에서 로그아웃한 접속자 ID를 삭제한 후 다시 user_list를 컨텍스트에 저장함
List user_list = (ArrayList)context.getAttribute("user_id");
user_list.remove(user_id);
context.removeAttribute("user_list");
context.setAttribute("user_list", user_list);
out.println("<br>로그아웃 했습니다.");
}
}
LoginImpl 클래스는 HttpSessionListener를 구현해 세션 생성과 소멸 시 이벤트를 처리하는 핸들러이다.
중요한 것은 앞의 LoginImpl에서 구현한 HttpSessionBindingListener와는 다르게 HttpSessionListener는 반드시 리스너를 구현한 이벤트 핸들러를 애너테이션을 이용해서 등록해야 한다는 것이다. 아래는 직접 구현하는 방법이다.
패키지 우클릭 -> New -> Listener 클릭
Class name으로 LoginImpl 입력 후 Next 클릭
HTTP session events의 Lifecycle javax.servlet.http.HttpSessionListener 체크 후 Next 클릭
Finish 클릭
@WebListener 애너테이션으로 리스너가 등록된 것을 확인
리스너를 등록한 이벤트 핸들러를 이용해 세션을 생성할 때는 sessionCreated( ) 메서드로 이벤트를 처리하고, 세션을 삭제할 때는 sessionDestroyed( ) 메서드로 이벤트를 처리한다.
package sec04.ex02;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener // HttpSessionBindingListener를 제외한 Listener를 구현한 모든 이벤트 핸들러는 반드시 애너테이션을 이용해 Listener로 등록해야 함
public class LoginImpl implements HttpSessionListener {
String user_id;
String user_pw;
static int total_user=0;
public LoginImpl() {
}
@Override
// 세션 생성 시 이벤트를 처리함
public void sessionCreated(HttpSessionEvent se) {
System.out.println("세션 생성");
++total_user;
}
@Override
// 세션 소멸 시 이벤트를 처리함
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("세션 소멸");
--total_user;
}
}
실행하면 사용자마다 로그인/로그아웃 시 접속자수와 접속자 ID를 표시한다.
먼저 첫 번째 아이디로 로그인한 결과이다.
두 번째 아이디 hong으로 로그인 한 결과이다.
그리고 hong 아이디로 로그인 한 익스플로러 창에서 로그아웃을 클릭하고, 크롬에서 재요청 하면 다음과 같이 접속자 수가 2에서 1로 감소한다.
다른 리스너에서도 세부 기능을 익히고 나면 고급 기능도 쉽게 구현이 가능하다.
'웹 개발 기초 > 자바 웹을 다루는 기술' 카테고리의 다른 글
JSP 페이지 구성 요소 (0) | 2023.02.27 |
---|---|
JSP 3단계 작업 과정 (0) | 2023.02.27 |
HttpSessionBindingListener 이용해 로그인 접속자 수 표시 (0) | 2023.02.23 |
여러 가지 서블릿 관련 Listener API (0) | 2023.02.22 |
Filter API (0) | 2023.02.22 |