實作類別似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>