IT虾米网

Listener监听器笔记1详解

luoye 2019年08月20日 编程语言 154 0

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,可以看到如下图的效果:

 

发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Servlet笔记1详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。