问题描述:
用户登陆后转到list.jsp页面,此页面不停向服务器请求数据。用户的登录名保存到session和servletContext的用户列表中一个list。当用户session失效的时候从用户列表中删除用户。
问题是:
虽然不停向服务器发送数据,但还是会在不到一分钟的时间内调用sessionDestroyed方法,难道此方法不是在session失效的时候才被调用?
下面贴出完整代码。
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>login</title>
</head>
<body style="text-align: center;">
<p style="margin-top: 200px;" />
<p>${error }</p>
<form action="login" method="post">
用户名:<input type="text" name="name"/>
<p/>
<input type="submit"/>
</form>
</body>
</html>
LoginServlet
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String name = req.getParameter("name");
List<String> list;
if(name==null||name.equals("")){
req.setAttribute("error", "登录名不能为空!");
req.getRequestDispatcher("login.jsp").forward(req, resp);
return;
}
//从ServletContext中取得已登录用户信息的容器,一个list
Object o = getServletContext().getAttribute("list");
if(o==null){
//如果没有,则创建一个并放入ServletContext
list = new ArrayList();
getServletContext().setAttribute("list", list);
}
else {
//有则返回
list = (List<String>)o ;
}
//如果当前登陆用户有重名的则,无法登陆
if(list.contains(name)){
req.setAttribute("error", "用户已存在!");
req.getRequestDispatcher("login.jsp").forward(req, resp);
return;
}
//将登陆用户放入ServletContext中的list
list.add(name);
getServletContext().setAttribute("list", list);
//将当前用户的用户名放入session
HttpSession session = req.getSession();
Logger.getLogger(this.getClass().getName()).info("原始会话超时时间为:"+session.getMaxInactiveInterval());
session.setMaxInactiveInterval(5); //设置当前会话的失效时间,单位是秒。即5秒不回应则判定离线
session.setAttribute("name", name);
Logger.getLogger(this.getClass().getName()).info("设定会话超时时间为:"+session.getMaxInactiveInterval());
req.setAttribute("list", list);
req.getRequestDispatcher("list.jsp").forward(req, resp);
}
}
list.jsp ,用到了jquery进行Ajax调用
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>login</title>
<style type="text/css">
.left{
width: 200px;
height: 600px;
float: left;
border: dashed 1px black;
}
.right{
width: 600px;
height: 600px;
margin-left: 220px;
border: dotted 1px black;
overflow: scroll;
}
</style>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<script type="text/javascript">
//如果返回类型定义为json,则无法重复执行,所以只能自己eval了。原因是jquery1.4解析json格式比较严格,这里返回的是不严格的json格式,致使解析失败。解决方法:1.返回严格的json格式数据2.自己eval生成json对象
$(function(){
function getText(){
$.post("control",function(data){
var json = eval("("+data+")");
//返回在线用户数组
var list = json.list;
var date = json.date; //服务器端返回的日期
var $left = $(".left");
var nameList = ""; //构造用户在线字符串形式,方便添加进html
for(var i in list){
nameList = nameList+"<li>"+list[i]+"</li>"
}
$left.empty().html("当前用户列表:<br/><ul>"+nameList+"</ul>");
$(".right").append("服务器端传来数据:"+date+'<br/>');
//继续请求服务器
getText();
});
}
//开始执行
getText();
});
</script>
</head>
<body>
<div class="left">
当前用户列表:
<p></p>
<ul>
<%
List<String> list = (List<String>)request.getAttribute("list");
for(String s:list){
%>
<li><%=s %></li>
<%} %>
</ul>
</div>
<div class="right">
</div>
</body>
</html>
ControlServlet
public class ControlServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String text;
List<String> list;
StringBuilder sb = new StringBuilder();
text = simpleDateFormat.format(new Date());
//取得在线的列表
Object o =getServletContext().getAttribute("list");
if(o==null) list = null;
else list = (List<String>)o;
//构造返回的String, json格式
sb.append("{list:[");
if(list==null){
//一个空的数组
sb.append("],");
}else{
for(int i=0;i<list.size();i++){
sb.append("\"");
sb.append(list.get(i));
sb.append("\"");
//如果是最后一个则不添加 ','
if(i!=list.size()-1) sb.append(",");
}
sb.append("],");
}
//把服务器返回的时间添加入json
sb.append("date:").append("\"").append(text).append("\"");
sb.append("}");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
//停留一秒后,然后再向客户端输出。如果不停留,则浏览器会不停处理,可能崩溃。
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//
}
//返回组装好的json字符串形式
out.print(sb.toString());
//Logger.getLogger(this.getClass().getName()).info("服务器段返回json的字符串为:\n"+sb.toString());
}
}
SessionListener
public class SessionListening implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
//从session中取得登陆的用户名
Object o = se.getSession().getAttribute("name");
//如果未登录则返回
if(o==null) return;
String name = (String)o;
//从ServletContext中获得登陆用户的容器
Object ob = se.getSession().getServletContext().getAttribute("list");
//如果容器为null,则返回
if(ob==null) return;
List<String> list = (List<String>)ob;
//从list中移除当前用户
if(list.contains(name)) list.remove(name);
//把改变后的list重新放入ServletContext
se.getSession().getServletContext().setAttribute("list", list);
Logger.getLogger("session").info("用户"+name+",退出!");
}
}
web.xml
<listener>
<listener-class>test.servlet.SessionListening</listener-class>
</listener>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>test.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>control</servlet-name>
<servlet-class>test.servlet.ControlServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>control</servlet-name>
<url-pattern>/control</url-pattern>
</servlet-mapping>
虽然设置session的失效时间在5秒,但是总是在大概1分钟的时候调用sessionDestroyed方法。
以上为全部工程文件,
等待高手解答
分享到:
相关推荐
在Session失效后,有时需要执行特定操作,例如控制在线用户数量或处理用户多次登录的问题。这时可以利用Servlet API中的监听器(Listener)来实现。监听器是Java Web应用程序中用于监听特定事件(如Session创建和...
* 空闲状态 2 分钟后,HttpSessionListener 中将被调用的方法是 `sessionDestroyed()` (问题 7)。 六、Eclipse 工具开发 Servlet * Eclipse 工具开发 Servlet 会自动将 src 目录下的文件编译成 class 文件存放到 `...
3. **会话超时管理**:你可以设置自定义的会话超时策略,比如在`sessionDestroyed()`中检查会话是否因为超时而销毁,如果是因为超时,则记录日志或执行其他操作。 4. **安全控制**:当用户登出时,除了清除Cookie,...
这种方式是最简单的实现单例的方式,但是它不考虑线程安全的问题,因此在多线程环境下可能会出现问题。示例如下: ```java public class Singleton { private static Singleton _instance = null; // 私有构造...
Servlet监听器是Java Web开发中的一个重要概念,它允许开发者在特定事件发生时执行代码,比如在Web应用程序启动、停止时,或者在用户会话创建、销毁时。这为程序员提供了更多的控制权,使得他们能够更好地管理和监控...
在`sessionDestroyed`方法中,我们可以检查会话的销毁原因,如果是因为超时或者其他特定条件(如用户请求注销),那么可以执行“踢人”操作,比如清理服务器上的用户信息,更新在线用户列表等。 至于提供的压缩包子...
这些Listener提供了在Servlet容器(如Tomcat)管理的生命周期事件上的扩展点,使得我们能够在恰当的时间执行自定义逻辑。 1. **ServletContextListener**: - 当Web应用启动时,容器会调用`contextInitialized()`...
这个问题通常出现在多用户系统中,系统需要确保一个用户在同一时间只能在一个设备或浏览器上保持登录状态,避免数据冲突和安全风险。下面我们将详细介绍如何通过session监听来实现这一功能。 首先,我们需要创建一...
在Session失效后,有时我们需要执行一些特定的操作,比如: - **控制并发用户数**:当Session失效时,系统中在线用户数会减少,这可以帮助限制系统的负载,保证系统性能在一个合理的范围内。 - **防止同一用户重复...
### 用户重复登录问题详解与解决方案 #### 一、问题背景及需求分析 在现代网络应用中,用户登录安全性和用户体验是非常重要的。一个常见的问题是:如何防止用户在一个客户端登录后,在另一个客户端进行重复登录?...
`sessionCreated` 指在Session创建时执行的方法,`sessionDestroyed` 指在Session失效时执行的方法。 例如: ```java public class SessionListener implements HttpSessionListener { public void ...
在session过期/调用了invalidate方法销毁session时,该监听器方法被执行public void sessionDestroyed(HttpSessionEvent httpSessionEvent)。 3. ServletRequestListener:监听ServletRequest域对象的创建、销毁。...
- 当会话结束(`sessionDestroyed()`),例如会话过期或用户显式调用`invalidate()`方法时,可以用来执行清理操作,如清除缓存数据。 3. **HttpSessionAttributeListener**: - 这个监听器用于监听会话中属性的...
`requestInitialized`可以在请求开始处理时进行操作,比如记录请求开始时间或添加额外的请求信息。`requestDestroyed`则在请求处理结束时执行,适合清理与请求相关的临时数据。 3. **HttpSessionListener**:针对...
为了每分钟统计一次在线人数,你可以使用`java.util.Timer`或`ScheduledExecutorService`来定期执行任务。在这个任务中,你可以遍历所有的`HttpSession`,统计有效的会话数量。此外,为了防止数据丢失,可以将统计...
Web监听允许开发者在特定的Web事件发生时执行自定义代码,例如Servlet上下文、会话或请求的生命周期事件。 首先,我们来看Servlet上下文监听。Servlet上下文(ServletContext)是整个Web应用共享的数据存储区域。...
然而,为了安全考虑,Session不会无限期地保持活跃状态,而是设置有一定的过期时间。本篇文章将详细介绍三种判断Session过期的方法。 ### 1. 检查Session有效期 这是最直接的方式,服务器在创建Session时会设置一...
在J2EE开发中,确保同一用户在同一时间只能有一个在线会话是非常重要的,这涉及到用户身份验证的安全性和系统资源的有效利用。标题提到的"J2EE 用监听器实现同一用户只能有一个在线"是指通过使用Java Servlet API中...
为了长期保存和统计历史访问量,你可能需要定时将内存中的日志数据持久化到数据库,并定期执行统计任务,例如计算过去一天、一周或一月的访问量。 总结,`HttpSessionListener`可以有效地帮助我们跟踪Web应用的在线...
每当用户打开一个新的页面或执行一个操作时,服务器都会为该用户创建一个唯一的Session ID,并将其保存在服务器端,同时将ID返回给客户端(通常是存储在Cookie中)。这样,每次客户端发送请求时,都会携带这个...