Listener監聽器實現在線用戶統計
1.前言
當大家剛開始接觸Java Web做項目時,掌握了Servlet後,也許對Listener監聽器的作用,以及代碼編寫並未能很好的掌握。本文通過實現在線用戶統計以及在線用戶列表的代碼實操,讓大家通過實際操作理解並能使用Listener監聽器。
2.業務場景
你是否想在項目中顯示一個在線人數而無從下手???
你是否想在自己的平臺上查看當前登錄的用戶列表???
本文通過JSP+Servlet+監聽器Listener爲你實現,花5分鐘一起來看看吧。
3.效果展示
打開不同的瀏覽器進行登錄。可以看到當前登錄的人數以及用戶列表。
當用戶退出時,則註銷當前用戶。並且看到在線用戶數量-1,以及用戶列表也減少該用戶。
4.代碼實現
4.1 項目結構
4.2 頁面準備
4.2.1 主頁(index.jsp)
index.jsp用於顯示當前登錄用戶(用戶存在Session中),以及顯示登錄人數與登錄用戶的列表記錄。還有login.jsp與register.jsp頁面的跳轉。由於登錄用戶的數據時存儲在application域中的,因此需要在index.jsp中先註冊,再登錄。則可以看到用戶登錄列表。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<title>主頁</title>
</head>
<body>
<h1>welcome to index.jsp!</h1>
<c:if test="${session_user!=null}">
歡迎您,${session_user.userName}
<a href="loginOut">退出</a>
<a href="">用戶列表</a>
</c:if>
<c:if test="${session_user==null}">
<a href="login.jsp">登錄</a>
<a href="register.jsp">註冊</a>
</c:if>
<a href="index.jsp">主頁</a>
<span style="color: red">${tip}</span>
<hr/>
<h3>在線用戶</h3>
當前在線用戶人數:[${fn:length(onlineUser)}]人
<br/>
用戶列表:<br/>
<c:forEach items="${onlineUser}" var="user" varStatus="u">
第[${u.index+1}]位,在線[${user}]用戶。<br/>
</c:forEach>
</body>
</html>
4.2.2 登錄頁(login.jsp)
PS:登錄前,請先去register.jsp中註冊用戶。此處沒有連接數據庫,數據存儲在緩存中。因此需要先註冊,才能進行登錄。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登錄頁面</h1>
<form action="login.do" method="post">
用戶:<input type="text" name="username">
<br/>
密碼:<input type="password" name="pwd"/>
<br/>
<input type="submit" value="登錄" />
</form>
<span style="color: red">${tip}</span>
</body>
</html>
4.2.3 註冊頁(register.jsp)
PS:註冊成功後,數據會存儲在application域中。當用戶登錄時,把用戶輸入與application域的數據進行比較,用戶存在則登錄成功。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>註冊頁面</h1>
<form action="register.do" method="post">
用戶:<input type="text" name="username">
<br/>
密碼:<input type="password" name="pwd"/>
<br/>
性別:<input type="radio" name="sex" value="1"/>男
<input type="radio" name="sex" value="0"/>女
<br/>
<input type="submit" value="註冊" />
</form>
</body>
</html>
4.2 Controller準備
4.2.1 處理登錄的Controller
@WebServlet(name = "LoginServlet", urlPatterns = "/login.do")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String pwd = request.getParameter("pwd");
//先從緩存中拿出users
ServletContext sc = request.getServletContext();
List<User> users = (List<User>) sc.getAttribute("users");
for (User u : users) {
if(u.getUserName().equals(username)&&u.getPwd().equals(pwd)){
//跳轉到index.jsp
HttpSession session = request.getSession();
session.setAttribute("session_user",u);
request.getRequestDispatcher("index.jsp").forward(request,response);
}
}
//提示用戶名密碼不正確
request.setAttribute("tip","用戶名密碼不正確!");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
4.2.2 處理退出的控制器
@WebServlet(name = "LoginOutServlet",urlPatterns = "/loginOut")
public class LoginOutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.removeAttribute("session_user");
request.setAttribute("tip","退出成功!");
request.getRequestDispatcher("index.jsp").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
4.2.3 註冊功能的控制器
@WebServlet(name = "RegisterServlet",urlPatterns = "/register.do")
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收參數
String username = request.getParameter("username");
String pwd = request.getParameter("pwd");
String sex = request.getParameter("sex");
User user = new User(username,pwd,Integer.parseInt(sex));
//把註冊用戶存儲起來
ServletContext sc = request.getServletContext();
List<User> users = (List<User>) sc.getAttribute("users");
//把user存到緩存中(application)
users.add(user);
sc.setAttribute("users",users);
request.setAttribute("tip","註冊成功!請登錄");
request.getRequestDispatcher("login.jsp").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
4.3 Listener監聽器編寫
監聽器中,瓜瓜寫了大量註釋。簡潔易懂,大家放心閱讀。
/**
*在線用戶監聽器
*/
@WebListener()
public class OnLineListener implements ServletContextListener,
HttpSessionListener, HttpSessionAttributeListener {
//創建一個application變量
ServletContext application = null;
// Public constructor is required by servlet spec
public OnLineListener() {
}
//監聽服務器啓動的method
public void contextInitialized(ServletContextEvent sce) {
System.out.println("------------服務器啓動了---------------");
//創建一個List<user>,並把該list存到application中
List<User> users = new ArrayList<>();
application = sce.getServletContext();
//創建一個onlineUser來存在線用戶
List<String> onlineUser = new ArrayList<>();
application.setAttribute("users",users);
application.setAttribute("onlineUser",onlineUser);
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("--------------服務器關閉了----------------");
}
// HttpSessionListener implementation
//session是基於服務器端創建的。當一個瀏覽器訪問服務器就會創建一個唯一session
public void sessionCreated(HttpSessionEvent se) {
System.out.println("-----session被創建了-----------");
/**
* 可以統計當前有多少人連接我們的服務器。(統計在線訪問人數)
*/
}
public void sessionDestroyed(HttpSessionEvent se) {
/* Session is destroyed. */
System.out.println("--------session被銷燬了------------");
/**
* 可以統計當前有多少人連接我們的服務器。(統計在線訪問人數)
*/
}
/*
attributeAdded()方法:監聽session執行setAttr()時觸發
統計登錄到該系統的用戶
*/
public void attributeAdded(HttpSessionBindingEvent sbe) {
System.out.println("-----session設值----"+sbe.getName()+","+sbe.getValue());
User user = (User) sbe.getValue();
//創建一個list來記錄在線用戶
HttpSession session = sbe.getSession();
application = session.getServletContext();
//先從緩存application域中拿到 onlineUser
List<String> onlineUser = (List<String>) application.getAttribute("onlineUser");
if(onlineUser.indexOf(user.getUserName())==-1){//新增加的userName在onlineUser中不存在
onlineUser.add(user.getUserName());
//存儲到application中
application.setAttribute("onlineUser",onlineUser);
}
}
/**
* attributeRemoved方法:監聽session.removeAttr(key,val)
* 當用戶退出時,則註銷,並且更新在線用戶數量與列表
*/
public void attributeRemoved(HttpSessionBindingEvent sbe) {
System.out.println("-----session銷燬----"+sbe.getName()+","+sbe.getValue());
//創建一個list來記錄在線用戶
HttpSession session = sbe.getSession();
application = session.getServletContext();
User user = (User) sbe.getValue();
//先從緩存application域中拿到 onlineUser
List<String> onlineUser = (List<String>) application.getAttribute("onlineUser");
onlineUser.remove(user.getUserName());
application.setAttribute("onlineUser",onlineUser);
}
public void attributeReplaced(HttpSessionBindingEvent sbe) {
}
}
5. 知識點總結
5.1 Listener讓我們更好的掌握4個作用域
Listener監聽器,可以監聽Session的創建與銷燬;也可以監聽application域的創建與銷燬;還可以Session域的setAttribute(key,val),removeAttribute(key,val)方法進行監聽。這些都需要我們對4個作用域有一定的理解與認識,才能更好的在開發中使用Listener監聽器。(4個作用域的區別還不會??趕緊點我)
5.2 Listener其他擴展
5.2.1 實現網站點擊率
sessionCreated(HttpSessionEvent se){}
sessionDestroyed(HttpSessionEvent se){}
當打開一個瀏覽器訪問項目127.0.0.1:8080/項目名,sessionCreated(){}方法就會被執行。而當關閉該瀏覽器時,則會執行sessionDestroyed(){}。因此,我們可以通過這2個方法,實現一個訪問人數,或者點擊率的功能。
5.2.2 服務器日誌
contextInitialized(ServletContextEvent sce){}
contextDestroyed(ServletContextEvent sce){}
這2個方法用於監聽application域,本篇博客,瓜瓜也使用了這2個方法來進行創建在線登錄人數List。這2個方法監聽了整個Web容器的生命週期,我們可以拓展很多功能。
6. 附上完整源代碼
源代碼下載:https://download.csdn.net/download/u010312671/12562328