• Listener监听器笔记1


    1.常用的Web事件监听器接口:

        1.ServletContextListener:用于监听Web应用的启动和关闭。

        2.ServletContextAttributeListener:用于监听ServletContext(application)范围内属性的改变。

        3.ServletRequestListener:用于监听用户的请求。 

        4.ServletRequestAttributeListener:用于监听ServletRequest范围(request)内属性的改变。

        5.HttpSessionListener:用于监听用户session的开始和结束。

        6.HttpSessionAttributeListener:用于监听HttpSession范围(session)内属性的改变。


    2.配置Listener
      1.使用@WebListener修饰Listener实现类即可;或者在web.xml中使用<listener.../>元素进行配置。

    3.使用HttpSessionListener示例:
      监听系统的在线用户:实现HttpSessionListener接口的监听器,可以监听每个用户会话的开始和断开,因此可以通过该监听器监听系统的在线用户

      后台监听器代码:

    /**
     * Description:监听在线用户
     * Author: Eleven
     * Date: 2018/1/8 11:17
     */
    @WebListener
    public class OnlineListener implements HttpSessionListener{
    
        //当用户与服务器之间开始session的时候触发该方法
        @Override
        public void sessionCreated(HttpSessionEvent httpSessionEvent) {
    
            HttpSession session = httpSessionEvent.getSession();
            //设置session有效时间为60秒
            session.setMaxInactiveInterval(60);
            System.out.println("创建"+session.getId()+",当前时间:"+System.currentTimeMillis());
            ServletContext application = session.getServletContext();
            //如果是一次新的会话
            if(session.isNew()){
                //获取session中的用户
                String user = (String) session.getAttribute("user");
                user = (user == null) ? "游客":user;
    
                Map<String,String> online = (Map<String, String>) application.getAttribute("online");
                if(online == null){
                    online = new Hashtable<String,String>();
                }
                //将用户在线信息放入map中
                online.put(session.getId(),user);
                application.setAttribute("online",online);
            }
        }
    
        //当用户与服务器之间session断开时触发该方法
        @Override
        public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
    
            System.out.println("用户与服务器之间session结束");
    
            HttpSession session = httpSessionEvent.getSession();
            System.out.println("销毁"+session.getId()+",当前时间:"+System.currentTimeMillis());
    
            ServletContext application = session.getServletContext();
    
            Map<String,String> online = (Map<String, String>) application.getAttribute("online");
            if(online != null){
                //删除该用户在线信息
                online.remove(session.getId());
            }
    
            application.setAttribute("online",online);
    
        }
    }

     页面jsp

    <%@ page import="java.util.Map" %><%--
      Created by IntelliJ IDEA.
      User: Administrator
      Date: 2018/1/4
      Time: 16:46
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>用户在线信息</title>
    </head>
    <body>
    
        在线用户:
        <table width="400" border="1">
        <%
            //获取application中的map
            Map<String,String> online = (Map<String, String>) application.getAttribute("online");
            for(String sessionId:online.keySet()){
        %>
            <tr>
                <td><%=sessionId%></td>
                <td><%=online.get(sessionId)%></td>
            </tr>
        <%
            }
        %>
        </table>
    </body>
    </html>

      接下来,在本机启动两个不同的浏览器来模拟三个用户访问该项目,访问online.jsp页面会看到有三个游客在线,如下图:

      至于为什么只用一个浏览器访问该项目的不同资源,却还是只有一个session,而打开不同的浏览器,就会创建session?这个问题,就留着之后在session中去解决哦~~

      虽然通过实现HttpSessionListener接口可以做到监听在线用户信息,但是这样比较粗糙,只能监听到多少人在线,如果要监听每个用户停留在哪个页面,用户访问的ip等信息,则应该使用HttpServletRequest来实现。

    4.使用ServletRequestListener+ServletContextListener示例:

      具体的做法思路:

      写一个类实现ServletRequestListener,这个监听器就负责监听用户的每次请求,当用户请求到达时,将用户请求的sessionId,用户名,用户IP,正在访问的资源,访问时间记录下来。

      写一个类实现ServletContextListener,随web应用的启动而启动,然后在程序里另开一条线程,这个线程每隔一段时间就去检查每条在线的记录,看每条记录的访问时间与当前时间的差是否超过了一个指定值,如果超过了,就将这条在线记录删掉。

      监听用户请求的代码:

    /**
     * Description:监听用户的每次请求
     * Author: Eleven
     * Date: 2018/1/8 15:33
     */
    @WebListener
    public class RequestListener implements ServletRequestListener{
    
        //当用户请求到达,被初始化时触发该方法
        @Override
        public void requestInitialized(ServletRequestEvent servletRequestEvent) {
    
            HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
            //session会话被创建
            HttpSession session = request.getSession();
            String sessionId = session.getId();
            //获取访问的ip和访问的页面
            String ip = request.getRemoteAddr();
    
            String page = request.getRequestURI();
            System.out.println("当前会话:"+sessionId+",访问ip:"+ip+",访问页面:"+page);
            //获取用户
            String user = (String) session.getAttribute("user");
            //未登录,设为游客
            user = (user == null) ? "游客":user;
    
            //从数据库中查询该sessionId所对应的用户信息
            try {
                DbDao dd = new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/test","root","123456");
    
                ResultSet rs =  dd.query2("select * from online where sessionId = '"+sessionId+"' ");
                //存在当前sessionId的用户信息,则表明是旧的会话
                if(rs.next()){
                    //修改访问的page以及当前的时间
                    rs.updateString(4,page);
                    rs.updateLong(5,System.currentTimeMillis());
                    rs.updateRow();
                    rs.close();
                }else{
                    //不存在,则存进数据库
                    dd.insert("insert into online values(?,?,?,?,?)",sessionId,user,ip,page,System.currentTimeMillis());
                }
    
                rs.close();
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //当用户请求结束,被销毁时触发该方法
        @Override
        public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
            HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
            String page = request.getRequestURI();
            System.out.println("访问结束"+page);
        }
    }

      随web应用而启动,用于检测每条在线记录的监听器代码:

    /**
     * Description: 随web项目启动而启动,然后另开一条线程去判断用户是否已经离线
     * Author: Eleven
     * Date: 2018/1/12 16:45
     */
    @WebListener
    public class TimeListener implements ServletContextListener{
    
        //超过该时间没有访问本站,即认为已经离线
        public final int MAX_MILLIS = 1000*10*2;//2分钟
    
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            //每1分钟检查一次
            new Timer(1000*60*1,new ActionListener(){
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        //从数据库中查询出所有的用户信息
                        DbDao dd = new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/test","root","123456");
                        ResultSet rs = dd.query("select * from online ");
                        StringBuffer sb = new StringBuffer();
                        sb.append("(");
                        while(rs.next()){
                            if(System.currentTimeMillis()-rs.getLong(5)>MAX_MILLIS){
                                //超过了10分钟
                                sb.append("'");
                                sb.append(rs.getString(1));
                                sb.append("',");
                            }
                        }
                        System.out.println("aa"+sb.toString());
                        //如果有需要删除的记录
                        if(sb.length()>1){
                            sb.setLength(sb.length()-1);
                            sb.append(")");
                            System.out.println(sb.toString());
                            dd.modify("delete from online where sessionId in " +sb.toString());
                            //删除超时的记录
                        }
                        System.out.println("需要移除的"+sb.toString());
                        rs.close();
                        dd.closeConn();
    
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    }
                }
            }).start();
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
    
        }
    }

      涉及到的数据库的操作的DbDao的代码:

    /**
     * Description:数据库操作
     * Author: Eleven
     * Date: 2018/1/6 9:27
     */
    public class DbDao {
        private Connection conn;
        private String driver;
        private String url;
        private String name;
        private String psw;
    
        public DbDao() {
        }
    
        public DbDao( String driver, String url, String name, String psw) {
            this.driver = driver;
            this.url = url;
            this.name = name;
            this.psw = psw;
        }
    
        //获取数据库连接
        public Connection getConnection() throws Exception{
    
            if(conn == null){
                //注册驱动
                Class.forName(driver);
                //获取连接
                conn = DriverManager.getConnection(url,name,psw);
            }
            return conn;
        }
        
    
        //查询1  动态查询
        public ResultSet query(String sql,Object... args) throws Exception{
    
            //创建Statement
            PreparedStatement pstmt = getConnection().prepareStatement(sql);
            //设置参数
            for(int i=0;i<args.length;i++){
                 pstmt.setObject(i+1,args[i]);
            }
            return pstmt.executeQuery();
        }
    
        //查询2 
        public ResultSet query2(String sql) throws Exception{
            Statement st = getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
    
            return st.executeQuery(sql);
        }
    
    
    
        //插入
        public boolean insert(String sql,Object... args) throws Exception{
            PreparedStatement pstmt = getConnection().prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                pstmt.setObject(i+1,args[i]);
            }
    
            if(pstmt.executeUpdate() != 1){
                return false;
            }
            return true;
        }
    
        //修改或删除
        public void modify(String sql,Object... args) throws Exception{
            PreparedStatement pstmt = getConnection().prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                pstmt.setObject(i+1,args[i]);
            }
            pstmt.executeUpdate();
            pstmt.close();
        }
    
        //关闭数据库连接
        public void closeConn() throws Exception{
            if(conn != null && !conn.isClosed()){
                conn.close();
            }
        }
    
        public Connection getConn() {
            return conn;
        }
    
        public void setConn(Connection conn) {
            this.conn = conn;
        }
    
        public String getDriver() {
            return driver;
        }
    
        public void setDriver(String driver) {
            this.driver = driver;
        }
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPsw() {
            return psw;
        }
    
        public void setPsw(String psw) {
            this.psw = psw;
        }
    }

      页面jsp代码:

    <%@ page import="java.sql.ResultSet" %>
    <%@ page import="servlet.DbDao" %><%--
      Created by IntelliJ IDEA.
      User: Administrator
      Date: 2018/1/4
      Time: 16:46
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>用户在线信息</title>
    </head>
    <body>
    
        在线用户:
        <table width="400" border="1">
        <%
            //从数据库总查询出所有的记录
            DbDao dd = new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/test","root","123456");
            ResultSet rs = dd.query("select * from online");
            while(rs.next()){
        %>
            <tr>
                <td><%=rs.getString(1)%></td>
                <td><%=rs.getString(2)%></td>
                <td><%=rs.getString(3)%></td>
                <td><%=rs.getString(4)%></td>
            </tr>
        <%
            }
        %>
        </table>
    </body>
    </html>

      最后打开不同的浏览器去访问该项目的不同页面,然后再去访问online2.jsp,可以看到如下图的效果:

  • 相关阅读:
    多线程环境下调用 HttpWebRequest 并发连接限制
    i—比 i++ 快?
    文件在不同文件系统间拷贝文件时间改变的问题
    Go websocket 聊天室demo2
    Go websocket 聊天室demo以及k8s 部署
    AcWing 1077. 皇宫看守
    AcWing 1073. 树的中心
    AcWing 1085. 不要62
    AcWing 1081 度的数量
    AcWing 1082. 数字游戏
  • 原文地址:https://www.cnblogs.com/eleven258/p/8277523.html
Copyright © 2020-2023  润新知