项目需要做一个统计在线登陆用户数量的功能。
首先我想到的是写HttpSessionListener监听,根据session来确定用户数量。
步骤:
web.xml配置HttpSessionListener监听
<listener> <listener-class>org.hd.base.listener.HDSessionListener</listener-class> </listener>
监听的类:
package org.hd.base.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.apache.log4j.Logger; import org.hd.util.ConstantDifinitionUtil; public class HDSessionListener implements HttpSessionListener { private static final Logger logger = Logger.getLogger(HDSessionListener.class.getName()); public void sessionCreated(HttpSessionEvent sessionEvent) { logger.error("HelpDesk system sessionCreated, sessionid=" + sessionEvent.getSession().getId()); } public void sessionDestroyed(HttpSessionEvent sessionEvent) { String userJobNumber=""; if(sessionEvent.getSession().getAttribute(ConstantDifinitionUtil.CURRENT_USER_ID)!=null){ userJobNumber=(String)sessionEvent.getSession().getAttribute(ConstantDifinitionUtil.CURRENT_USER_ID); } logger.error("HelpDesk system sessionDestroyed, sessionid=" + sessionEvent.getSession().getId() +";登录用户工号是:"+userJobNumber); } }
再写个类查看信息:
package org.hd.tempuser.action; import java.io.PrintWriter; import java.util.Iterator; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; import org.apache.struts2.ServletActionContext; import org.hd.tempuser.service.TempUserService; import org.rd.framework.common.container.ContainerManager; import org.rd.framework.struts.action.CommonAction; import com.opensymphony.xwork2.ActionContext; public class AllUserMonitorAction extends CommonAction{ private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(AllUserMonitorAction.class.getName()); private TempUserService tempUserService = (TempUserService)ContainerManager.getComponent(TempUserService.BEAN_ID); //查看在线所有用户 public String monitorAllUsersNow() throws Exception{ ActionContext ctx = ActionContext.getContext(); HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE); HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST); HttpSession session=request.getSession(); Map appMap=ctx.getApplication(); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); System.err.println("session的id是:"+session.getId()); session.setAttribute("haha", session.getId()); return SUCCESS; } //查看当前的sessionId以及属性"haha"的值 public String monitorUserInfoFromSession() throws Exception{ ActionContext ctx = ActionContext.getContext(); HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE); HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST); HttpSession session=request.getSession(); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); System.err.println("session的id是(session.getId()):"+session.getId()); System.err.println("从session的属性中取出的id是(session.getAttribute(\"haha\")):"+session.getAttribute("haha")); // out.println("YES"); return SUCCESS; } public String execute() throws Exception{ return SUCCESS; } }
开始测试:
第一个人访问登陆页面
<2012-12-11 14:46:00,977> ERROR (HDSessionListener.java:14) [http-80-1] (org.hd.base.listener.HDSessionListener) - HelpDesk system sessionCreated, sessionid=86938C672ADD0922845ED8DDD1575B6F
继续访问请求
http://helpdesk.citicsinfo.com/tempUser/monitorAllUsersNow.action
打印:
session的id是:86938C672ADD0922845ED8DDD1575B6F
访问请求
http://helpdesk.citicsinfo.com/tempUser/monitorUserInfoFromSession.action
打印:
session的id是(session.getId()):86938C672ADD0922845ED8DDD1575B6F
从session的属性中取出的id是(session.getAttribute("haha")):86938C672ADD0922845ED8DDD1575B6F
在第一个人未退出系统的情况下,第二个人访问该系统,
访问登陆页面:
打印:
<2012-12-11 14:50:25,941> ERROR (HDSessionListener.java:14) [http-80-3] (org.hd.base.listener.HDSessionListener) - HelpDesk system sessionCreated, sessionid=63C1C0FB9FB34F8263C23EA06FD46320
访问方法monitorAllUsersNow
打印:
session的id是:63C1C0FB9FB34F8263C23EA06FD46320
监控Monitor请求,经过过滤!
访问方法 monitorUserInfoFromSession
打印:
session的id是(session.getId()):63C1C0FB9FB34F8263C23EA06FD46320
从session的属性中取出的id是(session.getAttribute("haha")):63C1C0FB9FB34F8263C23EA06FD46320
监控Monitor请求,经过过滤!
第一个人继续访问方法 monitorUserInfoFromSession(查看属性haha的值)
打印:
session的id是(session.getId()):86938C672ADD0922845ED8DDD1575B6F
从session的属性中取出的id是(session.getAttribute("haha")):86938C672ADD0922845ED8DDD1575B6F
第二个人也继续访问方法 monitorUserInfoFromSession(查看属性haha的值)(注意此时这个人还不算是登陆成功)
打印:
session的id是(session.getId()):63C1C0FB9FB34F8263C23EA06FD46320
从session的属性中取出的id是(session.getAttribute("haha")):63C1C0FB9FB34F8263C23EA06FD46320
监控Monitor请求,经过过滤!
从上面的实验我们可以得出几个结论:
1:当客户端访问服务器时,服务器会检查jsessionId,看是不是同一个session。
如果是同一个,就那这个session进行处理;如果不是,就创建一个新的session。
服务器辨认session是通过sessionId的,不通的session有不通的id,所以每个客户端可以在session放相同属性名的值而不会
被覆盖。
2,一般登陆是需要验证的,即用户名和密码正确才算是登陆成功。
如果登录失败,session已经创建了,以这个作为在线用户的依据,从逻辑上就是错的!
这个作为点击量或者访问量还是可以的。
3,即使关闭浏览器,session还是存在的。所以当用户退出系统时,要把session失效。
session.invalidate();
这样监听才会有输出,表明这个session被Destroyed。
<2012-12-11 15:14:00,818> ERROR (HDSessionListener.java:22) [http-80-4] (org.hd.base.listener.HDSessionListener) - HelpDesk system sessionDestroyed, sessionid=86938C672ADD0922845ED8DDD1575B6F;登录用户工号是:
所以从session中获取的用户账号当然是null了。
为了获取准确的在线登陆的用户的数量,使用HttpSessionListener监听这个方法是不行的,必须要改变思路。
我的思路是:
修改登陆和退出的类,在登陆成功后使用application对象保存当前用户的sessionId和账号(作为键值对保存),
在退出系统时,从application对象中遍历取出所有值(还有其他值,你保存的值最好有记号或者规律),
这样就把所有登陆用户的账号和sessionId拿到了,把当前要退出系统的sessionId和账号remove掉。
这样作为全局变量的application对象就作为一个我们存储所有当前登陆用户的容器,只要维护好这个容器,
就能保证在线人数的数值是正确的。
现在我们修改查看当前所有在线人数的那个类AllUserMonitorAction
package org.hd.tempuser.action; import java.io.PrintWriter; import java.util.Iterator; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; import org.apache.struts2.ServletActionContext; import org.hd.tempuser.service.TempUserService; import org.rd.framework.common.container.ContainerManager; import org.rd.framework.struts.action.CommonAction; import com.opensymphony.xwork2.ActionContext; public class AllUserMonitorAction extends CommonAction{ private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(AllUserMonitorAction.class.getName()); private TempUserService tempUserService = (TempUserService)ContainerManager.getComponent(TempUserService.BEAN_ID); //查看在线所有用户 public String monitorAllUsersNow() throws Exception{ ActionContext ctx = ActionContext.getContext(); HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE); HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST); HttpSession session=request.getSession(); Map appMap=ctx.getApplication(); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); // System.err.println("session的id是:"+session.getId()); // session.setAttribute("haha", session.getId()); if(appMap!=null){ Iterator it=appMap.keySet().iterator(); for(;it.hasNext();){ Object key=it.next(); Object value=appMap.get(key.toString()); System.out.println("App;ication中的键值对,key:"+key+",value:"+value); } } return SUCCESS; } //查看当前的sessionId以及属性"haha"的值 public String monitorUserInfoFromSession() throws Exception{ ActionContext ctx = ActionContext.getContext(); HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE); HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST); HttpSession session=request.getSession(); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); System.err.println("session的id是(session.getId()):"+session.getId()); System.err.println("从session的属性中取出的id是(session.getAttribute(\"haha\")):"+session.getAttribute("haha")); // out.println("YES"); return SUCCESS; } public String execute() throws Exception{ return SUCCESS; } }
同时修改登陆和退出系统的代码:
登录成功时,在application对象中放入键值对:sessionId和账号
如:
ActionContext ctx = ActionContext.getContext();
HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
HttpSession session = request.getSession();
if(登陆成功){
ctx.getApplication().put("HelpDeskSession"+session.getId(), 账号);//前面的字符串是为了更容易寻找
}
在退出系统时:
if(session.getId()!=null){
ctx.getApplication().remove("HelpDeskSession"+session.getId());
}
方案已经有了,现在开始写代码和测试
第一个人登陆后,我们访问monitorAllUsersNow方法
打印:
Application中的键值对,key:org.apache.catalina.WELCOME_FILES,value:[Ljava.lang.String;@1021349
Application中的键值对,key:AxisEngine,value:org.apache.axis.server.AxisServer@76e297
Application中的键值对,key:org.apache.AnnotationProcessor,value:org.apache.catalina.util.DefaultAnnotationProcessor@11e71f9
Application中的键值对,key:org.apache.catalina.jsp_classpath,value:/xx
Application中的键值对,key:org.springframework.web.context.support.ServletContextScope,value:org.springframework.web.context.support.ServletContextScope@119bde5
Application中的键值对,key:org.apache.jasper.runtime.JspApplicationContextImpl,value:org.apache.jasper.runtime.JspApplicationContextImpl@14039d5
Application中的键值对,key:org.apache.catalina.resources,value:org.apache.naming.resources.ProxyDirContext@19504ee
Application中的键值对,key:javax.servlet.context.tempdir,value:D:\HelpDesk\workSpace\ROOT\WebContent\WEB-INF\classes
Application中的键值对,key:org.springframework.web.context.WebApplicationContext.ROOT,value:Root WebApplicationContext: startup date [Tue Dec 11 16:02:04 CST 2012]; root of context hierarchy
Application中的键值对,key:HelpDeskSession2C6D2B26AB0BC498923FE8DD4799CBEB,value:T000851.当前在线
Application中的键值对,key:CONFIGURATION_CONTEXT,value:org.apache.axis2.context.ConfigurationContext@11654e0
Application中的键值对,key:AdminServletAxisEngine,value:org.apache.axis.server.AxisServer@76e297
所有在线人数是1
第二个人登陆后,在访问这个方法,
打印:
Application中的键值对,key:org.apache.catalina.WELCOME_FILES,value:[Ljava.lang.String;@1021349
Application中的键值对,key:AxisEngine,value:org.apache.axis.server.AxisServer@76e297
Application中的键值对,key:org.apache.catalina.resources,value:org.apache.naming.resources.ProxyDirContext@19504ee
Application中的键值对,key:HelpDeskSessionBF0009485F6E34FA23F4DD7DCE5BF96D,value:T001890.当前在线
Application中的键值对,key:org.springframework.web.context.WebApplicationContext.ROOT,value:Root WebApplicationContext: startup date [Tue Dec 11 16:02:04 CST 2012]; root of context hierarchy
Application中的键值对,key:CONFIGURATION_CONTEXT,value:org.apache.axis2.context.ConfigurationContext@11654e0
Application中的键值对,key:AdminServletAxisEngine,value:org.apache.axis.server.AxisServer@76e297
Application中的键值对,key:org.springframework.web.context.support.ServletContextScope,value:org.springframework.web.context.support.ServletContextScope@119bde5
Application中的键值对,key:org.apache.catalina.jsp_classpath,value:/xxx
Application中的键值对,key:org.apache.AnnotationProcessor,value:org.apache.catalina.util.DefaultAnnotationProcessor@11e71f9
Application中的键值对,key:org.apache.jasper.runtime.JspApplicationContextImpl,value:org.apache.jasper.runtime.JspApplicationContextImpl@14039d5
Application中的键值对,key:javax.servlet.context.tempdir,value:D:\HelpDesk\workSpace\ROOT\WebContent\WEB-INF\classes
Application中的键值对,key:HelpDeskSession2C6D2B26AB0BC498923FE8DD4799CBEB,value:T000851.当前在线
所有在线人数是2
然后第二个人再退出系统后我们再访问
打印:
Application中的键值对,key:org.apache.catalina.WELCOME_FILES,value:[Ljava.lang.String;@1021349
Application中的键值对,key:AxisEngine,value:org.apache.axis.server.AxisServer@76e297
Application中的键值对,key:org.apache.AnnotationProcessor,value:org.apache.catalina.util.DefaultAnnotationProcessor@11e71f9
Application中的键值对,key:org.apache.catalina.jsp_classpath,value:/xxx
Application中的键值对,key:org.springframework.web.context.support.ServletContextScope,value:org.springframework.web.context.support.ServletContextScope@119bde5
Application中的键值对,key:org.apache.jasper.runtime.JspApplicationContextImpl,value:org.apache.jasper.runtime.JspApplicationContextImpl@14039d5
Application中的键值对,key:org.apache.catalina.resources,value:org.apache.naming.resources.ProxyDirContext@19504ee
Application中的键值对,key:javax.servlet.context.tempdir,value:D:\xxx
Application中的键值对,key:org.springframework.web.context.WebApplicationContext.ROOT,value:Root WebApplicationContext: startup date [Tue Dec 11 16:02:04 CST 2012]; root of context hierarchy
Application中的键值对,key:HelpDeskSession2C6D2B26AB0BC498923FE8DD4799CBEB,value:T000851.当前在线
Application中的键值对,key:CONFIGURATION_CONTEXT,value:org.apache.axis2.context.ConfigurationContext@11654e0
Application中的键值对,key:AdminServletAxisEngine,value:org.apache.axis.server.AxisServer@76e297
所有在线人数是1
好,现在已经可以成功获取正确数据,修改登陆和退出,我们把客户端的IP地址记录下来。
String remoteAddr=request.getRemoteAddr()==null?"":request.getRemoteAddr();
ctx.getApplication().put("HelpDeskSession"+request.getSession().getId(), getUname()+"suolong"+remoteAddr);
下面就是对数据的处理,拼装成json,在页面做个列表。
最后的代码:
package org.hd.tempuser.action; import java.io.PrintWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Iterator; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; import org.apache.struts2.ServletActionContext; import org.hd.tempuser.service.TempUserService; import org.hd.util.ReportUtil; import org.rd.framework.common.container.ContainerManager; import org.rd.framework.struts.action.CommonAction; import com.opensymphony.xwork2.ActionContext; public class AllUserMonitorAction extends CommonAction{ private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(AllUserMonitorAction.class.getName()); private TempUserService tempUserService = (TempUserService)ContainerManager.getComponent(TempUserService.BEAN_ID); //查看在线所有用户 public String monitorAllUsersNow() throws Exception{ ActionContext ctx = ActionContext.getContext(); HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE); HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST); HttpSession session=request.getSession(); Map appMap=ctx.getApplication(); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); // System.err.println("session的id是:"+session.getId()); // session.setAttribute("haha", session.getId()); String resJson=""; String numJson=""; String listJson="\"listdata\":["; int count=0; if(appMap!=null){ Iterator it=appMap.keySet().iterator(); for(;it.hasNext();){ Object key=it.next(); String keyStr=key.toString(); Object value=appMap.get(keyStr); String valueStr=value.toString(); String[] arr=valueStr.split("suolong"); String jobNumber=(arr.length>=1)?arr[0]:""; String userIP=(arr.length>=2)?arr[1]:""; //本机IP要另写方法实现 if(userIP.equals("127.0.0.1")){ userIP=this.getLocalIP(); } if(keyStr.startsWith("HelpDeskSession")){ //System.out.println("Application中的键值对,key:"+keyStr+",value:"+valueStr+".当前在线"); String strJson="{\"jobNumber\":\""+jobNumber+"\",\"userIP\":\""+userIP+"\"}"; if(count==0){ listJson+=strJson; }else{ listJson+=","+strJson; } count++; }else{ //System.out.println("Application中的键值对,key:"+keyStr+",value:"+valueStr); } }// end for }//end if numJson="\"numJson\":{\"count\":\""+count+"\"}"; listJson+="]"; resJson="{"+numJson+ ","+listJson+"}"; out.println(resJson); System.out.println("resJson是"+resJson); return NONE; } //查看当前的sessionId以及属性"haha"的值 public String monitorUserInfoFromSession() throws Exception{ ActionContext ctx = ActionContext.getContext(); HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE); HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST); HttpSession session=request.getSession(); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); System.err.println("session的id是(session.getId()):"+session.getId()); System.err.println("从session的属性中取出的id是(session.getAttribute(\"haha\")):"+session.getAttribute("haha")); // out.println("YES"); return SUCCESS; } //获取本机实际IP public static String getLocalIP() { InetAddress LocalIP =null; try { LocalIP = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } return LocalIP.getHostAddress(); } public String execute() throws Exception{ return SUCCESS; } }
jsp页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <%@ taglib uri="/WEB-INF/component.tld" prefix="cx"%> <%@ taglib uri="/WEB-INF/greenpage.tld" prefix="page"%> <%@ page import="java.util.*" %> <%@ page import="org.hd.util.ReportUtil" %> <%@ page import="org.rd.framework.query.support.PaginationSupport" %> <% String path = request.getContextPath(); %> <% %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Single Series Column 2D Chart</title> <script src="<%=path%>/script/jquery-1.7.1.js" type="text/javascript"></script> <link href="<%=path%>/resource/hd/css/style2.css" rel="stylesheet" type="text/css" /> <script src="<%=path%>/resource/tool/hometab/Style/menu.js" type="text/javascript"></script> <link rel="stylesheet" href="<%=path%>/resource/tool/hometab/Style/default.css" type="text/css" /> <script src="<%=path%>/script/hd/greenpage.js" type="text/javascript"></script> </script> </head> <body style=" overflow-y:scroll;overflow-x:auto;"> <input type="hidden" id="path" value="<%=path%>" /> <div style="width:100%;height:10px"></div> <h3 style="text-align: center;vertical-align:bottom;padding: 0px,0px,5px,0px; margin: 0px,0px,5px,0px; font-size:14px;color: #0c212b; "> 在线用户列表</h3> <div style="width:100%;height:10px"></div> <table width="100%" border="0" align="center" style="margin-left: 220px;"> <tr> <td style="width:100%;"> <div > <table> <tr style=" margin: 8px,0px,5px,0px;"> <td style="width:10%"></td> <td style="width:5%;align:center"></td> <td id="countNum" style="width:30%;color:red;"> 合计: </td> <td style="width:5%"><input type="button" id="chaxun" onclick="shuaxin()" value="刷新"></td> <td style="width:5%"> </td> </tr> </table> </div> </td> </tr> <tr> <td style="width:100%;align:center"> <div id="tablelist" > <table style="margin : 0px 0px 0px 0px;position: relative;left: 0px;top: 0px; width="100%" height="100%" border="0" cellspacing="0" cellpadding="0" id="box_mid"> <tr> <td class="right"><!--列表--> <div class="divline2" > <table width="800px" border="0" cellspacing="0" cellpadding="0" class="tables2"> <tr id="tableheaders"> <th width="45%">IP地址</th> <th width="45%">坐席工号 </th> </tr> </table> </div> <div style="height:200px; overflow-y:none;width:100%;"> <table width="100%" border="0" cellspacing="0" cellpadding="0" class="table4" id="list"> <div id="listdata"> <tr> <td width="45%"></td> <td width="45%"></td> </tr> </div> </table> </div> <!--列表END--></td> </tr> </table> <div id="divpage" style="align:center"></div> </div> </td> </tr> <tr> <td style="width:100%"> </td> </tr> <tr> <td style="width:100%"> </td> </tr> </table> </body> </html> <script type="text/javascript"> var path=document.getElementById("path").value; shuaxin(); //刷新 var num=1; function shuaxin(){ var urlpath=path+'/tempUser/monitorAllUsersNow.action?randomstr='+Math.random(); $.ajax({ type: "POST", url: urlpath, success: chaxunBackDealData, dataType:"json" }); } function chaxunBackDealData(data){ num++; // {"numJson":{"count":"2"},"listdata":[{"jobNumber":"T001890","userIP":"127.0.0.1"}]} var count=data.numJson.count; var listdata=data.listdata; var heji="合计:"+count; if(num%2==0){ $("#countNum").css("color","green"); }else{ $("#countNum").css("color","red"); } $("#countNum").html(heji); var tablehtml=""; for(var i=0;i<listdata.length;i++){ //alert(listdata[i].agent_count); var jobNumber=listdata[i].jobNumber; var userIP=listdata[i].userIP; var htmlstr="<tr>"; htmlstr+="<td width=\"45%\">"+userIP+"</td>"; htmlstr+="<td width=\"46%\">"+jobNumber+"</td>"; htmlstr+="</tr>"; tablehtml+=htmlstr; } $("#list").html(tablehtml); } </script>
效果: