实现类似QQ登陆功能,账号已在一处登陆,在另外一处登陆时,将挤掉前一次的登录。
原理简介:
主要是servlet中对用户登录时的处理,servlet中维护了用户和sessionId的关系以及用户和session的关系,保存在两个map中,当用户登录时会向map中新增一条记录,如果
发现map中已经有了该用户,则将该用户对应的记录删掉,注意是将map中的记录删掉而不是将session销毁,然后在该session中放入给用户提示的信息,再将新用户的信息
放入map中。在页面中需要不断的验证session中有没有提示信息,如果有则说明已经被挤掉,有一点要注意的是,jsp中获取到的session中的attribute是不会自动更新的,也
就是说如果不刷新页面,即使servlet已经向该用户的session中放入了提示信息,页面中也不会得到的,所以这里我们需要用Ajax的方式不断的向服务器发送请求以获取
session中用户提示信息的动态,一旦发现session中有提示信息,就给出提示。
项目结构:

web.xml
-
<?xml version="1.0" encoding="UTF-8"?> -
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> -
<display-name>LoginPush</display-name> -
<listener> -
<listener-class>cn.com.hafx.LoginServlet</listener-class> -
</listener> -
<servlet> -
<servlet-name>login</servlet-name> -
<servlet-class>cn.com.hafx.LoginServlet</servlet-class> -
</servlet> -
<servlet-mapping> -
<servlet-name>login</servlet-name> -
<url-pattern>/login.do</url-pattern> -
<url-pattern>/reLogin.do</url-pattern> -
<url-pattern>/getUserMsg.do</url-pattern> -
</servlet-mapping> -
<welcome-file-list> -
<welcome-file>login.jsp</welcome-file> -
</welcome-file-list> -
</web-app>
LoginServlet.java
-
import java.io.IOException; -
import java.io.PrintWriter; -
import java.util.HashMap; -
import java.util.Map; -
import javax.servlet.ServletException; -
import javax.servlet.http.HttpServlet; -
import javax.servlet.http.HttpServletRequest; -
import javax.servlet.http.HttpServletResponse; -
import javax.servlet.http.HttpSession; -
import javax.servlet.http.HttpSessionEvent; -
import javax.servlet.http.HttpSessionListener; -
import org.apache.commons.logging.Log; -
import org.apache.commons.logging.LogFactory; -
/** -
* -
* @author lyh -
* @version 2013-4-11 -
* @see LoginServlet -
* @since -
*/ -
public class LoginServlet extends HttpServlet implements HttpSessionListener -
{ -
/** -
* 序列号 -
*/ -
private static final long serialVersionUID = -2080934157550504694L; -
/** -
* 日志 -
*/ -
private static Log log = LogFactory.getLog(LoginServlet.class); -
/** -
* 用户和Session绑定关系 -
*/ -
public static final Map<String, HttpSession> USER_SESSION = new HashMap<String, HttpSession>(); -
/** -
* seeionId和用户的绑定关系 -
*/ -
public static final Map<String, String> SESSIONID_USER = new HashMap<String, String>(); -
/** -
* 实现HttpSessionListener接口监听 监听session的创建事件 -
*/ -
@Override -
public void sessionCreated(HttpSessionEvent se) -
{ -
String sessionId = se.getSession().getId(); -
log.info("创建session sessionId= " + sessionId); -
} -
/** -
* 实现HttpSessionListener接口监听 监听session的销毁事件 -
*/ -
@Override -
public void sessionDestroyed(HttpSessionEvent se) -
{ -
String sessionId = se.getSession().getId(); -
//当前session销毁时删除当前session绑定的用户信息 -
//同时删除当前session绑定用户的HttpSession -
USER_SESSION.remove(SESSIONID_USER.remove(sessionId)); -
log.info("销毁session sessionId= " + sessionId); -
} -
/** -
* 用户登录 -
*/ -
@Override -
protected void service(HttpServletRequest request, HttpServletResponse response) -
throws ServletException, IOException -
{ -
//获取请求命令 -
request.setCharacterEncoding("utf-8"); -
String servletPath = request.getServletPath(); -
String uri = servletPath.substring(1, servletPath.lastIndexOf(".do")); -
try -
{ -
//登录 -
if ("login".equals(uri)) -
{ -
HttpSession session = request.getSession(); -
String userName = request.getParameter("userName"); -
String password = request.getParameter("password"); -
if (userName != null && !"".equals(userName.trim())) -
{ -
//登录成功 -
if (login(userName, password)) -
{ -
//处理用户登录(保持同一时间同一账号只能在一处登录) -
userLoginHandle(request); -
//添加用户与HttpSession的绑定 -
USER_SESSION.put(userName.trim(), session); -
//添加sessionId和用户的绑定 -
SESSIONID_USER.put(session.getId(), userName); -
log.info("用户[" + userName + "] 已上线..."); -
session.setAttribute("userName", userName); -
session.removeAttribute("userMsg"); -
//重定向到首页 -
response.sendRedirect("main.jsp"); -
} -
//登录失败 -
else -
{ -
log.info("用户[" + userName + "] 登录失败..."); -
request.setAttribute("msg", "登录失败,请重新登录!"); -
//response.sendRedirect("login.jsp"); -
request.getRequestDispatcher("login.jsp").forward(request, response); -
} -
} -
else -
{ -
log.info("用户[" + userName + "] 登录失败..."); -
request.setAttribute("msg", "登录失败,请重新登录!"); -
//response.sendRedirect("login.jsp"); -
request.getRequestDispatcher("login.jsp").forward(request, response); -
} -
} -
//重新登陆 -
else if ("reLogin".equals(uri)) -
{ -
HttpSession session = request.getSession(); -
String userName = (String)session.getAttribute("userName"); -
if (session != null) -
{ -
//销毁相关session -
//USER_SESSION.remove(SESSIONID_USER.remove(session.getId())); -
session.invalidate(); -
} -
if (userName != null && !"".equals(userName)) -
{ -
log.info("用户[" + userName + "] 已下线..."); -
} -
//重定向到登录页面 -
response.sendRedirect("login.jsp"); -
} -
//ajax校验 -
else if ("getUserMsg".equals(uri)) -
{ -
HttpSession session = request.getSession(); -
response.setContentType("text/html"); -
response.setCharacterEncoding("utf-8"); -
PrintWriter out = response.getWriter(); -
out.print(session.getAttribute("userMsg")); -
} -
} -
catch (Exception e) -
{ -
log.error(e.getClass() + e.getMessage()); -
PrintWriter out = response.getWriter(); -
out.print("服务器内部错误!"); -
} -
} -
/** -
* -
* Description:用户登录时的处理 <br> -
* @param request -
* @see -
*/ -
private void userLoginHandle(HttpServletRequest request) -
{ -
//当前登录的用户 -
String userName = request.getParameter("userName"); -
//当前sessionId -
//String sessionId = request.getSession().getId(); -
//删除当前sessionId绑定的用户,用户--HttpSession -
//USER_SESSION.remove(SESSIONID_USER.remove(sessionId)); -
//删除当前登录用户已绑定的HttpSession -
HttpSession session = USER_SESSION.remove(userName); -
if (session != null) -
{ -
//删除已登录的sessionId绑定的用户 -
SESSIONID_USER.remove(session.getId()); -
session.removeAttribute("userName"); -
session.setAttribute("userMsg", "您的账号已经在另一处登录,您被迫下线!"); -
} -
} -
/** -
* -
* Description: 模拟DB登录判断<br> -
* @param userName 用户 -
* @param password 密码 -
* @return -
* @see -
*/ -
private boolean login(String userName, String password) -
{ -
return ("lyh".equals(userName) && "123456".equals(password)); -
} -
}
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>登录</title> -
<% -
String msg = (String)(request.getAttribute("msg")==null?"":request.getAttribute("msg")); -
%> -
<script type="text/javascript"> -
function show(){ -
if('<%=msg%>'!=''){ -
alert('<%=msg%>'); -
} -
} -
</script> -
</head> -
<body style="text-align: center" onload="show();"> -
<form action="login.do" method="post"> -
<table border="1"> -
<tr> -
<td align="center" colspan="2"> -
<h3>用户登录</h3> -
</td> -
</tr> -
<tr> -
<td align="right"> -
用户名 -
</td> -
<td align="left"> -
<input type="text" id="userName" name="userName"> -
</td> -
</tr> -
<tr> -
<td align="right"> -
密 码 -
</td> -
<td align="left"> -
<input type="password" id="password" name="password"> -
</td> -
</tr> -
<tr> -
<td align="center" colspan="2"> -
<input type="submit" value="登录"> -
-
<input type="reset" value="重置"> -
</td> -
</tr> -
</table> -
</form> -
</body> -
</html>
main.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>登录成功</title> -
<script type="text/javascript" src="js/jquery-1.4.4.min.js"></script> -
</head> -
<% -
response.setHeader("Pragma","No-cache"); -
response.setHeader("Cache-Control","No-cache"); -
response.setDateHeader("Expires", -1); -
response.setHeader("Cache-Control", "No-store"); -
String userName = ""; -
userName = (String)(session.getAttribute("userName")==null?"":session.getAttribute("userName")); -
%> -
<script type="text/javascript"> -
var int; -
var userMsg = ''; -
var i =0; -
function checkUserOnline(){ -
$.ajax({ -
type:"post", -
url:"getUserMsg.do", -
dataType : "text", -
success:function(data){userMsg = data;}, -
error:function(){ -
alert("获取用户信息失败!"); -
clearInterval(int); -
reLogin(); -
} -
}); -
if(userMsg=='null'||userMsg==''){ -
return; -
} -
else{ -
alert(userMsg); -
clearInterval(int); -
reLogin(); -
} -
} -
function reLogin(){ -
window.location = "reLogin.do"; -
} -
function checkLogin(){ -
int = setInterval("checkUserOnline()",500); -
} -
</script> -
<body onload="checkLogin()"> -
<% -
if(!"".equals(userName)){ -
out.print("登陆成功!<br/>用户名:<span id='userName'>"+userName+"</span><br/><input type='button' value='重新登陆' onclick='reLogin();'/>"); -
} -
%> -
</body> -
</html>
本文介绍了一种实现类似QQ登录功能的方法,确保同一账号只能在一处登录,若再次登录将挤掉前次登录。通过在servlet中维护用户与sessionId的关系,使用两个map来跟踪用户状态,结合Ajax轮询检查session中的提示信息,实现实时通知用户被挤下线。
5139

被折叠的 条评论
为什么被折叠?



