我用代碼教會你(三):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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章