JSP+SERVLET實現後登陸用戶擠掉之前登錄用戶
項目簡介
該項目是一個很簡單的測試項目,主要實現了用戶登錄時對於同一個用戶名後一用戶登錄擠掉前一用戶的功能,雖然項目很簡單,但是實現的功能卻是很有參考價值的。
功能示例
首先進入登錄頁面(用戶名wuyang,密碼不輸):
然後第一個用戶登錄:
接着登錄第二個用戶:
第二個用戶登錄後第一個用戶的頁面會立即彈出提示,並轉到登錄頁面(無刷新):
原理簡介
主要是servlet中對用戶登錄時的處理,servlet中維護了用戶和sessionId的關係以及用戶和session的關係,保存在兩個map中,當用戶登錄時會向map中新增一條記錄,如果發現map中已經有了該用戶,則將該用戶對應的記錄刪掉,注意是將map中的記錄刪掉而不是將session銷燬,然後在該session中放入給用戶提示的信息,再將新用戶的信息放入map中。再頁面中需要不斷的驗證session中有沒有提示信息,如果有則說明已經被擠掉,有一點要注意的是,jsp中獲取到的session中的Attribute是不會自動更新的,也就是說如果不刷新頁面,即使servlet已經向該用戶的session中放入了提示信息,頁面中也不會得到的,所以這裏我們需要用Ajax的方式不斷的向服務器發送請求以獲取session中用戶提示信息的動態,一旦發現session中有提示信息,就給出提示。
項目代碼
(注:jquery-1.4.2.min.js請自己下載)
login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%
String path =request.getContextPath();
String basePath =request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
String msg =(String)(request.getAttribute("msg")==null?"":request.getAttribute("msg"));
//System.out.println("msg:"+msg);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is mypage">
<!--
<link rel="stylesheet" type="text/css"href="styles.css">
-->
</head>
<script type="text/javascript">
function show(){
if('<%=msg%>'!=''){
alert('<%=msg%>');
}
}
</script>
<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 aling="right">
用戶名
</td>
<td align="left">
<input type="text" id="userName" name="userName">
</td>
</tr>
<tr>
<td aling="right">
密 碼
</td>
<td align="left">
<input type="text" 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=gbk" pageEncoding="gbk"%>
<html>
<head>
<title>主頁</title>
<Meta http-equiv="Content-Type" Content="text/html;Charset=gbk">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is mypage">
<script type="text/javascript" src="./jquery-1.4.2.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 toLogin(){
window.location = "./login.jsp";
}
function checkLogin(){
int = setInterval("checkUserOnline()",500);
}
</script>
<body onload="checkLogin()">
<%
if(!"".equals(userName)){
out.print("登陸成功!<br/>用戶名:<span id='userName'>"+userName+"</span><br/><inputtype='button' value='重登陸' οnclick='reLogin();'/>");
}
%>
</body>
</html>
user.LoginServlet
package user;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjavax.servlet.http.HttpSession;
importjavax.servlet.http.HttpSessionEvent;
importjavax.servlet.http.HttpSessionListener;
public class LoginServlet extends HttpServlet implements HttpSessionListener{
/**
* 用戶和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的銷燬和創建事件
*/
public void sessionDestroyed(HttpSessionEvent se) {
StringsessionId=se.getSession().getId();
//當前session銷燬時刪除當前session綁定的用戶信息
//同時刪除當前session綁定用戶的HttpSession
USER_SESSION.remove(SESSIONID_USER.remove(sessionId));
System.out.println("銷燬session:"+sessionId);
}
public void sessionCreated(HttpSessionEvent arg0) {
String sessionId = arg0.getSession().getId();
System.out.println("創建session:"+sessionId);
}
/**
* 用戶登錄時的處理
* 處理一個賬號同時只有一個地方登錄的關鍵
* @param request
*/
public static voiduserLoginHandle(HttpServletRequest request){
//當前登錄的用戶
StringuserName=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_USER.remove(session.getId());
session.removeAttribute("userName");
session.setAttribute("userMsg", "您的賬號已經在另一處登錄了,你被迫下線!");
}
}
/**
* 用戶登錄
*/
protected void service(HttpServletRequest request,
HttpServletResponseresponse) throws ServletException,IOException {
//獲取請求命令
request.setCharacterEncoding("gbk");
String servletPath = request.getServletPath();
String uri = servletPath.substring(1,servletPath.lastIndexOf(".do"));
//System.out.println("uri:"+uri);
try{
if("login".equals(uri)){//登錄
HttpSession session=request.getSession();
String userName=request.getParameter("userName");
Stringpassword=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);
System.out.println("用戶["+userName+"]已上線");
session.setAttribute("userName", userName);
session.removeAttribute("userMsg");
response.sendRedirect("main.jsp");
}else{
System.out.println("用戶["+userName+"]登錄失敗");
request.setAttribute("msg","登錄失敗,請重新登錄");
//response.sendRedirect("login.jsp");
request.getRequestDispatcher("login.jsp").forward(request,response);
//注意:上面的代碼如果沒有放在try中,將無法傳遞參數msg
}
}else{
System.out.println("用戶["+userName+"]登錄失敗");
request.setAttribute("msg","登錄失敗,請重新登錄");
//response.sendRedirect("login.jsp");
request.getRequestDispatcher("login.jsp").forward(request,response);
//注意:上面的代碼如果沒有放在try中,將無法傳遞參數msg給jsp
}
}else if("reLogin".equals(uri)){//重登陸
HttpSession session=request.getSession();
String userName = (String)session.getAttribute("userName");
if(session!=null){
USER_SESSION.remove(SESSIONID_USER.remove(session.getId()));
session.invalidate();
}
if(userName!=null&&!"".equals(userName))System.out.println("用戶["+userName+"]下線");
response.sendRedirect("login.jsp");
}else if("getUserMsg".equals(uri)){
HttpSession session=request.getSession();
String CONTENT_TYPE = "text/html; charset=GBK";
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
//System.out.println(session.getAttribute("userMsg"));
out.print(session.getAttribute("userMsg"));
}
}catch(Exception e){
e.printStackTrace();
PrintWriter out= response.getWriter();
out.print("服務器內部出錯!");
}
}
//對比用戶輸入的信息是否合法,從而判斷是否登錄成功
private boolean login(String userName,String password){
return "wuyang".equals(userName);
}
}