通过监听Session对象的方式来实现在线人数的统计和在线人信息展示,并且让超时的自动销毁
1. web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 统计在线人数--> <listener> <listener-class>com.wri.itmag.OnlineCounterListener</listener-class> </listener> <!-- session超时定义,单位为分钟 update by ChangPeng 2014-04-24 session超时时间设置为30分钟 --> <session-config> <session-timeout>30</session-timeout> </session-config> </web-app>
2.OnlineCounterListener.java
对Session对象实现监听,首先必须继承HttpSessionListener类,该程序的基本原理就是当浏览者访问页面的时候必定会产生一个session对象;当关闭该页面的时候必然会删除该session对象。所以每当产生一个新的session对象就让在线人数加1,当删除一个session对象就让在线人数减1。还要继承一个HttpSessionAttributeListener,来实现对其属性的监听。分别实现attributeAdded方法,attributeReplace方法以及attributeRemove方法。
sessionCreated//新建一个会话时候触发也可以说是客户端第一次和服务器交互时候触发
sessionDestroyed//销毁会话的时候 一般来说只有某个按钮触发进行销毁 或者配置定时销毁 ( 很多文献中提到说浏览器关闭时候会销毁 但是楼主通过各种现行主流浏览器测试效果不尽如人意)
HttpSessionAttributeListener有3个接口需要实现
attributeAdded//在session中添加对象时触发此操作 笼统的说就是调用setAttribute这个方法时候会触发的
attributeRemoved//修改、删除session中添加对象时触发此操作 笼统的说就是调用 removeAttribute这个方法时候会触发的
attributeReplaced//在Session属性被重新设置时
1 package com.wri.itmag; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.HashSet; 6 import java.util.List; 7 import java.util.Map; 8 import java.util.Set; 9 10 import javax.servlet.http.HttpSessionAttributeListener; 11 import javax.servlet.http.HttpSessionBindingEvent; 12 import javax.servlet.http.HttpSessionEvent; 13 import javax.servlet.http.HttpSessionListener; 14 15 import com.wri.itmag.vo.personalInfo.UserVO; 16 17 public class OnlineCounterListener implements HttpSessionListener, 18 HttpSessionAttributeListener { 19 public static int onLineCount; // 用于统计在线人数 20 /** 21 * 查询在线人名称,用于前台页面对于在线人名称的展示 22 */ 23 public static Set<String> onLinePersonList = new HashSet<String>();//用于 24 /** 25 * 用于查询在线人详细信息 26 */ 27 private Map<String, Object> sessionMap = new HashMap<String, Object>(); 28 29 public void sessionCreated(HttpSessionEvent hse) { 30 // HttpSession session = hse.getSession(); 31 // sessionMap.put(session.getId(), session); 32 // onLineCount = sessionMap.size(); 33 } 34 35 public void sessionDestroyed(HttpSessionEvent hse) { 36 // onLineCount = sessionMap.size(); 37 } 38 39 public void attributeAdded(HttpSessionBindingEvent hsbe) { 40 41 String name = hsbe.getName(); 42 if ("userVO".equals(name)) { 43 UserVO userVO = (UserVO) hsbe.getValue(); 44 sessionMap.put(userVO.getId() + "", userVO); 45 onLineCount = sessionMap.size(); 46 onLinePersonList.add(userVO.getUser_name()); 47 } 48 } 49 50 public void attributeRemoved(HttpSessionBindingEvent hsbe) { 51 String name = hsbe.getName(); 52 if ("userVO".equals(name)) { 53 UserVO userVO = (UserVO) hsbe.getValue(); 54 sessionMap.remove(userVO.getId() + ""); 55 onLineCount = sessionMap.size(); 56 //System.out.println(userVO.getId() + "" + userVO.getUser_name()); 57 onLinePersonList.remove(userVO.getUser_name()); 58 } 59 60 } 61 62 public void attributeReplaced(HttpSessionBindingEvent hsbe) { 63 64 String name = hsbe.getName(); 65 if ("userVO".equals(name)) { 66 UserVO userVO = (UserVO) hsbe.getValue(); 67 sessionMap.remove(userVO.getId() + ""); 68 onLineCount = sessionMap.size(); 69 onLineCount++; 70 onLinePersonList.remove(userVO.getUser_name()); 71 } 72 } 73 74 }
3.LoginAction.java
实现用户登录,登出,以及登录成功页面跳转的功能
1 package com.wri.itmag.action.login; 2 3 import java.io.IOException; 4 import java.text.SimpleDateFormat; 5 import java.util.ArrayList; 6 import java.util.Arrays; 7 import java.util.Date; 8 import java.util.List; 9 10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServletRequest; 12 import javax.servlet.http.HttpServletResponse; 13 import javax.servlet.http.HttpSession; 14 15 import net.sf.json.JSONObject; 16 17 import com.wri.itmag.OnlineCounterListener; 18 import com.wri.itmag.action.BaseAction; 19 import com.wri.itmag.common.LoginUserLog; 20 import com.wri.itmag.service.personalInfo.UserInfoService; 21 import com.wri.itmag.service.syscfg.DataDictManageService; 22 import com.wri.itmag.vo.personalInfo.UserVO; 23 24 public class LoginAction extends BaseAction { 25 private UserInfoService userInfoService; 26 private String userAccount; 27 private String password; 28 29 /** 30 * 登录操作 31 */ 32 public String login() throws Exception { 33 UserVO userVO = null; 34 HttpSession session = this.getSession(); 35 try { 36 userVO = userInfoService.checkUser(userAccount, password); 37 38 } catch (Exception e) { 39 e.printStackTrace(); 40 throw e; 41 } 42 try { 43 if (userVO != null) { 44 HttpServletRequest request = this.getRequest(); 45 // 登陆信息 46 LoginUserLog loginUserLog = new LoginUserLog(userVO.getId(), 47 request.getRemoteAddr()); 48 // 放入session 49 session.setAttribute("loginUserLog", loginUserLog); 50 session.setAttribute("userVO", userVO); 51 session.setAttribute("userJson", JSONObject.fromObject(userVO)); 52 this.outJsonString("{success:true,message:'登陆成功'}"); 53 } else { 54 this.outJsonString("{success:false,message:'请检查用户名和密码....'}"); 55 } 56 } catch (Exception ex) { 57 ex.printStackTrace(); 58 throw ex; 59 } 60 return null; 61 } 62 63 64 /** 65 * 用户退出 66 */ 67 public String logout() throws Exception { 68 HttpSession session = this.getSession(); 69 70 // 从session中获取用户信息 71 UserVO userVO = (UserVO) session.getAttribute("userVO"); 72 LoginUserLog loginUserLog = (LoginUserLog) session 73 .getAttribute("loginUserLog"); 74 if (loginUserLog != null) { 75 if (loginUserLog.isExist(loginUserLog.getUid())) { 76 session.setAttribute("loginUserLog", null); 77 session.setAttribute("userVO", null); 78 session.invalidate(); 79 } 80 } 81 82 // session.setAttribute("userVO", null); 83 // session.invalidate(); 84 85 this.outJsonString("{success:true}"); 86 return null; 87 } 88 89 /** 90 * 登录成功操作 91 */ 92 public String loginSucc() throws ServletException, IOException { 93 // 传递角色 94 HttpSession session = this.getSession(); 95 UserVO userVO = (UserVO) session.getAttribute("userVO"); 96 this.outJsonString("{success:true,userVO:'" 97 + JSONObject.fromObject(userVO) + "',isMyDemand:'" + isMyDemand 98 + "'}"); 99 return null; 100 } 101 102 /** 103 * 登陆成功后跳转到主界面 104 */ 105 public String jump() throws ServletException, IOException { 106 HttpSession session = this.getSession(); 107 HttpServletRequest request = this.getRequest(); 108 HttpServletResponse response = this.getResponse(); 109 if (session.isNew()) { 110 response.sendRedirect("login.html"); 111 } else { 112 UserVO userVO = (UserVO) session.getAttribute("userVO"); 113 if (userVO != null) { 114 request.setAttribute("userVO", userVO); 115 request.setAttribute("logTime", new SimpleDateFormat( 116 "yyyy-MM-dd").format(new Date())); 117 request.setAttribute("onlineCount", 118 OnlineCounterListener.onLineCount); 119 120 request.setAttribute("onLinePersonList", 121 OnlineCounterListener.onLinePersonList); 122 request.getRequestDispatcher("/WEB-INF/main.jsp").forward( 123 request, response); 124 } else { 125 response.sendRedirect("login.html"); 126 } 127 } 128 return null; 129 } 130 }
4.main.jsp 做页面展示 :在登陆完成后跳转到主页面就会显示在线人数,鼠标移至人数上时候,就会显示所有在线人信息,鼠标移出就自动隐藏。
... <span title="" style="font-size: 13px; font-family: 宋体; position: absolute; right: 5px; 80px;" onmouseover="showOnLinePersonList()" onmouseout="hideOnLinePersonList()"> 在线:${onlineCount}人 </span> <span id="onlinePersonList" style="display:none;font-size: 13px; font-family: 宋体; position: absolute; top:10px ;right: 10px; 80px;"> <div id="firstDiv" align="center" style="backgroud-color:#8069ff ;border-style:solid;border-1px">所有在线人</div> <div id="secondDiv" align="center"> <c:forEach items="${onLinePersonList}" var ="list"> <ol ><c:out value="${list}"/> </ol> </c:forEach> </div> </span> ..... <script> function showOnLinePersonList(){ document.getElementById('onlinePersonList').style.display="block"; } function hideOnLinePersonList(){ document.getElementById('onlinePersonList').style.display="none"; } </script>
未解决的问题:以上的代码可以成功的实现在线人数的统计,但是对于在线展示在线人信息的时候,还有bug存在。出现的情况为:如果在同一个客户端,一个用户登录之后,没有做登出的操作(即session没有销毁),此时再以另一个用户登录,这个时候就相当于session中的name为“uservo”的attribute被替换了,也就调用了OnlineCounterListener类中的attributeReplace方法,代码如下:onLinePersonList先要remove掉之前的用户,加入新的用户,但是attributeRemoved(HttpSessionBindingEvent hsbe)中hsbe.getValue()拿到的是之前的值,没法拿到新的用户的值,所以不知道如何把新登录的这个用户加到set里面去,求解!!!
if ("userVO".equals(name)) {
UserVO userVO = (UserVO) hsbe.getValue();
sessionMap.remove(userVO.getId() + "");
onLineCount = sessionMap.size();
onLineCount++;
onLinePersonList.remove(userVO.getUser_name());
}