网站建设
  简约型网页设计套餐998
  实惠型网站建设套餐2580
  综合型网站制作套餐4980
  网站改版与网站维护
  行业网站建设方案
  大型网站建设解决方案
  企业网站建设流程
  帝网科技网站设计与网站制作
建站FAQ
·网站空间问题解答
·企业邮箱问题解答
 
酷站欣赏
·房产酷站(379)
·综合门户(8 9)
·建筑装饰(603)
·手机通讯(354)
·生活购物(376)
·医疗保健(199)
·文化摄影(602)
·休闲体育(399)
>>更多酷站欣赏
网站优化
·Google(谷歌)优化   ·百度(BaiDu)优化
·雅虎(Yahoo)优化    ·Alexa排名优化   
·Google AdSense   ·DMOZ目录提交  
建站知识
·网站建设知识·网站名词解释·网站运营知识
·网络营销知识·搜索引擎知识·实用技术文摘
网站推广
百度网站推广 google网站推广
搜狐网站推广 网易网站推广
新浪网站推广   雅虎网站推广
  您当前位置: 当前位置:帝网科技 >> web开发 >> JSP专栏 >> 浏览文章
 
 
关于JSP中基于Session的在线用户统计分析
作者:乐乐整理 来源:帝网科技 日期:2008年08月10日 点击数:


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超时。如果需要实现刷新模型,就必须使用这种每个叶面进行刷新判断的方法。
 

  相关文章
 
·如何建立JSP操作以提高数据库访问效率
·servlet 生成静态HTML的方法
·使用JSP实现简易的SQL报表
·浅析Servlet和Jsp中的多国语言显示
·JSP/Servlet/JSF:自定义标签的另类体
·使用JSP+javascript打造二级级联下
·实例:JSP结合XML+XSLT将输出转换HTML
·JSP教程:JSP页面跳转的实战规则
·关于JSP中的offsetparent
·JSP中errorPage设置方法
·JSP用bean获取各种参数
·JSP基础知识教程
·在Eclipse中部署Tomcat,并运行JSP
·jsp教程:深入浅出URL编码
·JSP技术优缺点深入分析(2)
·Jsp环境下ajax乱码问题的解决方法
·JSP技术优缺点深入分析(1)
·jsp上传组件smartupload介绍
·JSP中文字符乱码处理的2种方法
·jsp入门:Jsp运行原理
 
 

公司环境 | 合作伙伴 | 人才招聘 | 付款方式 | 关于我们

地址:广州市天河区中山大道中120号D805 电话:020-82529556 传真:020-82529556
广州帝网网络科技有限公司 版权所有 粤ICP备08119341号