问题描述:
用户登陆后转到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方法。
以上为全部工程文件,
等待高手解答