统计在线已登录用户数量并获取客户端IP(涉及HttpSessionListener监听)
项目需要做一个统计在线登陆用户数量的功能。
首先我想到的是写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:[email protected]
Application中的键值对,key:org.apache.AnnotationProcessor,value:[email protected]
Application中的键值对,key:org.apache.catalina.jsp_classpath,value:/xx
Application中的键值对,key:org.springframework.web.context.support.ServletContextScope,value:[email protected]de5
Application中的键值对,key:org.apache.jasper.runtime.JspApplicationContextImpl,value:[email protected]
Application中的键值对,key:org.apache.catalina.resources,value:[email protected]
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:[email protected]
Application中的键值对,key:AdminServletAxisEngine,value:[email protected]
所有在线人数是1
第二个人登陆后,在访问这个方法,
打印:
Application中的键值对,key:org.apache.catalina.WELCOME_FILES,value:[Ljava.lang.String;@1021349
Application中的键值对,key:AxisEngine,value:[email protected]
Application中的键值对,key:org.apache.catalina.resources,value:[email protected]
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:[email protected]
Application中的键值对,key:AdminServletAxisEngine,value:[email protected]
Application中的键值对,key:org.springframework.web.context.support.ServletContextScope,value:[email protected]de5
Application中的键值对,key:org.apache.catalina.jsp_classpath,value:/xxx
Application中的键值对,key:org.apache.AnnotationProcessor,value:[email protected]
Application中的键值对,key:org.apache.jasper.runtime.JspApplicationContextImpl,value:[email protected]
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:[email protected]
Application中的键值对,key:org.apache.AnnotationProcessor,value:[email protected]
Application中的键值对,key:org.apache.catalina.jsp_classpath,value:/xxx
Application中的键值对,key:org.springframework.web.context.support.ServletContextScope,value:[email protected]de5
Application中的键值对,key:org.apache.jasper.runtime.JspApplicationContextImpl,value:[email protected]
Application中的键值对,key:org.apache.catalina.resources,value:[email protected]
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:[email protected]
Application中的键值对,key:AdminServletAxisEngine,value:[email protected]
所有在线人数是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>
效果: