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