分享
 
 
 

JSP环境基于Session的在线用户统计深入分析

王朝java/jsp·作者佚名  2006-05-15
窄屏简体版  字體: |||超大  

JSP环境基于Session的在线用户统计深入分析

JSP作为后起之秀能够在服务器编程环境中占据一定地位,是和它良好支持一系列业界标准

密切相关的。Session就是它提供的基础设施之一。作为一个程序员,你可以不介意具体在

客户端是如何实现,就方便的实现简单的基于session的用户管理。

现在对于处理在线用户,有几种不同的处理方法。

一种是叶面刷新由用户控制,服务器端控制一个超时时间比如30分钟,到了时间之后用户

没有动作就被踢出。这种方法的优点是,如果用户忘了退出,可以防止别人恶意操作。

缺点是,如果你在做一件很耗时间的事情,超过了这个时间限制,submit的时候可能要

再次面临登陆。如果原来的叶面又是强制失效的话,就有可能丢失你做的工作。在实现

的角度来看,这是最简单的,Server端默认实现的就是这样的模式。

另一种方式是,站点采用框架结构,有一个Frame或者隐藏的iframe在不断刷新,这样你

永远不会被踢出,但是服务器端为了判断你是否在线,需要定一个发呆时间,如果超过

这个发呆时间你除了这个自动刷新的叶面外没有刷新其他叶面的话,就认为你已经不在

线了。采取这种方式的典型是xici.net。 他的优点是可以可以利用不断的刷新实现一些

类似server-push的功能,比如网友之间发送消息。

不管哪一种模式,为了实现浏览当前所有的在线用户,还需要做一些额外的工作。

servlet API中没有得到Session列表的API。

可以利用的是Listener. Servlet 2.2和2.3规范在这里略微有一些不一样。

2.2中HttpSessionBindingListener可以实现当一个HTTPSession中的Attribute变化的

时候通知你的类。而2.3中还引入了HttpSessionAttributeListener.鉴于我使用的环境

是Visual age for java 4和JRun server 3.1,他们还不直接支持Servlet 2.3的编程,

这里我用的是HttpSessionBindingListener.

需要做的事情包括做一个新的类来实现HttpSessionBindingListener接口。这个接口有

两个方法:

public void valueBound(HttpSessionBindingEvent event),和

public void valueUnbound(HttpSessionBindingEvent event)。

当你执行Session.addAttribute(String,Object)的时候,如果你已经把一个实现了

HttpSessionBindingListener接口的类加入为Attribute,Session会通知你的类,调用

你的valueBound方法。相反,Session.removeAttribute方法对应的是valueUndound方法。

public class HttpSessionBinding implements javax.servlet.http.HttpSessionBindingListener

{

ServletContext application = null;

public HttpSessionBinding(ServletContext application)

{

super();

if (application ==null)

throw new IllegalArgumentException("Null application is not accept.");

this.application = application;

}

public void valueBound(javax.servlet.http.HttpSessionBindingEvent e)

{

Vector activeSessions = (Vector) application.getAttribute("activeSessions");

if (activeSessions == null)

{

activeSessions = new Vector();

}

JDBCUser sessionUser = (JDBCUser)e.getSession().getAttribute("user");

if (sessionUser != null)

{

activeSessions.add(e.getSession());

}

application.setAttribute("activeSessions",activeSessions);

}

public void valueUnbound(javax.servlet.http.HttpSessionBindingEvent e)

{

JDBCUser sessionUser = (JDBCUser)e.getSession().getAttribute("user");

if (sessionUser == null)

{

Vector activeSessions = (Vector) application.getAttribute("activeSessions");

if (activeSessions != null)

{

activeSessions.remove(e.getSession().getId());

application.setAttribute("activeSessions",activeSessions);

}

}

}

}

假设其中的JDBCUser类是一个任意User类。

在执行用户登录时,把User类和HttpSessionBinding类都加入到Session中去。

这样,每次用户登录后,在application中的attribute "activeSessions"这个vector中

都会增加一条记录。

每当session超时,valueUnbound被触发,在这个vector中删去将要被超时的session.

public void login()

throws ACLException,SQLException,IOException

{

/* get JDBC User Class */

if (user != null)

{

logout();

}

{

// if session time out, or user didn't login, save the target url temporary.

JDBCUserFactory uf = new JDBCUserFactory();

if ( (this.request.getParameter("userID")==null)

|| (this.request.getParameter("password")==null) )

{

throw new ACLException("Please input a valid userName and password.");

}

JDBCUser user =

(JDBCUser) uf.UserLogin(

this.request.getParameter("userID"),

this.request.getParameter("password") );

user.touchLoginTime();

this.session.setAttribute("user",user);

this.session.setAttribute("BindingNotify",new HttpSessionBinding(application));

}

}

Login的时候,把User和这个BindingNotofy目的的类都加入到session中去。

logout的时候,就要主动在activeSessions这个vector中删去这个session.

public void logout()

throws SQLException,ACLException

{

if (this.user == null

&& this.session.getAttribute("user")==null)

{

return;

}

Vector activeSessions = (Vector) this.application.getAttribute("activeSessions");

if (activeSessions != null)

{

activeSessions.remove(this.session);

application.setAttribute("activeSessions",activeSessions);

}

java.util.Enumeration e = this.session.getAttributeNames();

while (e.hasMoreElements())

{

String s = (String)e.nextElement();

this.session.removeAttribute(s);

}

this.user.touchLogoutTime();

this.user = null;

}

这两个函数位于一个HttpSessionManager类中.这个类引用了jsp里面的application全局

对象。

这个类的其他代码和本文无关且相当长,我就不贴出来了。

下面来看看jsp里面怎么用。

假设一个登录用的表单被提交到doLogin.jsp, 表单中包含UserName和password域。

节选部分片段:

<%

HttpSessionManager hsm = new HttpSessionManager(application,request,response);

try

{

hsm.login();

}

catch ( UserNotFoundException e)

{

response.sendRedirect("InsufficientPrivilege.jsp?detail=User%20does%20not%20exist.");

return;

}

catch (InvalidPasswordException e2)

{

response.sendRedirect("InsufficientPrivilege.jsp?detail=Invalid%20Password");

return;

}

catch ( Exception e3)

{

%>Error:<%=e3.toString() %><br>

Press <a href="login.jsp">Here</a> to relogin.

<%return;

}

response.sendRedirect("index.jsp");

%>

再来看看现在我们怎么得到一个当前在线的用户列表。

<body bgcolor="#FFFFFF">

<table cellspacing="0" cellpadding="0" width="100%">

<tr >

<td style="width:24px">SessionId

</td>

<td style="width:80px" >User

</td>

<td style="width:80px" >Login Time

</td>

<td style="width:80px" >Last access Time

</td>

</tr>

<%

Vector activeSessions = (Vector) application.getAttribute("activeSessions");

if (activeSessions == null)

{

activeSessions = new Vector();

application.setAttribute("activeSessions",activeSessions);

}

Iterator it = activeSessions.iterator();

while (it.hasNext())

{

HttpSession sess = (HttpSession)it.next();

JDBCUser sessionUser = (JDBCUser)sess.getAttribute("user");

String userId = (sessionUser!=null)?sessionUser.getUserID():"None";

%>

<tr>

<td nowrap=''><%= sess.getId() %></td>

<td nowrap=''><%= userId %></td>

<td nowrap=''>

<%= BeaconDate.getInstance( new java.util.Date(sess.getCreationTime())).getDateTimeString()%></td>

<td class="<%= stl %>3" nowrap=''>

<%= BeaconDate.getInstance( new java.util.Date(sess.getLastAccessedTime())).getDateTimeString()%></td>

</tr>

<%

}

%>

</table>

</body>

以上的代码从application中取出activeSessions,并且显示出具体的时间。其中

BeaconDate类假设为格式化时间的类。

这样,我们得到了一个察看在线用户的列表的框架。至于在线用户列表分页等功能,

与本文无关,不予讨论。

这是一个非刷新模型的例子,依赖于session的超时机制。我的同事sonymusic指出很

多时候由于各个厂商思想的不同,这有可能是不可信赖的。考虑到这种需求,需要在

每个叶面刷新的时候都判断当前用户距离上次使用的时间是否超过某一个预定时间值。

这实质上就是自己实现session超时。

如果需要实现刷新模型,就必须使用这种每个叶面进行刷新判断的方法。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有