最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java Web開發(fā)防止多用戶重復(fù)登錄的完美解決方案

 更新時(shí)間:2016年11月08日 09:18:52   作者:夜空中苦逼的程序員  
在web項(xiàng)目開發(fā)中,很多情況下都可以讓同一個(gè)賬號(hào)信息在不同的登錄入口登錄很多次,這樣子做的不是很完善。一般解決這種情況有兩種解決方案,小編呢主要以第二種方式給大家介紹具體的實(shí)現(xiàn)方法,對(duì)java web 防止多用戶重復(fù)登錄的解決方案感興趣的朋友一起看看吧

目前web項(xiàng)目中,很多情況都是可以讓同一個(gè)賬戶信息在不同的登錄入口登錄這次,這樣子就不那么美好了。

推薦閱讀:

Java 多用戶登錄限制的實(shí)現(xiàn)方法

現(xiàn)在有兩種解決方案:

1、將用戶的登錄信息用一個(gè)標(biāo)志位的字段保存起來,每次登錄成功就標(biāo)記1,注銷登錄就標(biāo)記為0,當(dāng)標(biāo)記為1的時(shí)候不允許別人登錄。

2、將用戶的登錄信息保存在application內(nèi)置作用域內(nèi), 然后利用session監(jiān)聽器監(jiān)聽每一個(gè)登錄用戶的登錄情況。

很顯然,第一種方式 每次登錄 都需要操作數(shù)據(jù)庫,多了一些不必要的性能開銷,而且在登錄狀態(tài)下 萬一突然電腦關(guān)閉了,那就永遠(yuǎn)都不能登錄了,可用性比較低。

但是第二種方式就不一樣了,可操作性強(qiáng),很方便維護(hù)所有在線用戶的信息。

接下來 主要介紹第二種方式的具體實(shí)現(xiàn):

1、在處理登錄的login方法中,先查詢數(shù)據(jù)庫驗(yàn)證下該用戶是否存在,如果存在 判斷該登錄賬戶是否已經(jīng)鎖定了, 然后從application內(nèi)置作用域?qū)ο笾腥〕鏊械牡卿浶畔?,查看該username賬戶是否已經(jīng)登錄,如果登錄了,就友好提示下,反之表示可以登錄,將該登錄信息以鍵值對(duì)的方式保存在application中。

代碼如下:

//沒有使用零配置前 每個(gè)訪問的方法都要加上@Action ,否則404 
@Action(value="login", results={ 
@Result(name="index", location="index.jsp"), 
}) 
public String login() throws Exception { 
try{ 
User result = userService.login(user.getFuUserName(), user.getFuPassword()); 
if(result!=null){ 
if(result.getFuStatus()!=null && result.getFuStatus()==0){ 
super.setRequestAttr(Constant.MESSAGE, "抱歉,該用戶已被鎖定!"); 
return "error"; 
} 
Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP); 
boolean isExist = false; 
String sessionId = super.getSessionId(false); 
if(loginUserMap==null){ 
loginUserMap = new HashMap<String, String>(); 
} 
for (String username : loginUserMap.keySet()) { 
//判斷是否已經(jīng)保存該登錄用戶的信息 或者 如果是同一個(gè)用戶進(jìn)行重復(fù)登錄那么允許登錄 
if(!username.equals(result.getFuUserName()) || loginUserMap.containsValue(sessionId)){ 
continue; 
} 
isExist = true; 
break; 
} 
if(isExist){ 
super.setRequestAttr(Constant.MESSAGE, "抱歉,該用戶已登錄!"); 
return "error"; 
}else { 
loginUserMap.put(result.getFuUserName(), sessionId); 
} 
//登錄成功 
super.setSessionAttr(Constant.LOGIN_USER, result); 
super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap); 
logger.info(result.getFuUserName() + " 登錄成功!"); 
//如果 session中fromUrl有值,就跳轉(zhuǎn)到該頁面 
String fromUrl = (String)super.getSessionAttr(Constant.FROM_URL); 
if(fromUrl!=null){ 
super.setSessionAttr(Constant.FROM_URL, null); 
super.getResponse().sendRedirect(fromUrl.toString()); 
return null; 
} 
return "index"; 
} 
} 
catch (Exception e) { 
e.printStackTrace(); 
logger.info("登錄失敗: "+e.getMessage()); 
} 
super.setRequestAttr("message", "用戶名或密碼錯(cuò)誤"); 
return "error"; 
}

2、登錄入口處理完之后,考慮到會(huì)話結(jié)束的話,那么對(duì)應(yīng)的登錄用戶也應(yīng)該相應(yīng)的注銷登錄。我們可以寫一個(gè)Session監(jiān)聽器,監(jiān)聽sessioon銷毀的時(shí)候,我們將登錄的用戶注銷掉,也就是從application中移除。表示該用戶已經(jīng)下線了。

代碼如下:

package com.facelook.util; 
import java.util.Map; 
import javax.servlet.http.HttpSessionEvent; 
import javax.servlet.http.HttpSessionListener; 
import org.apache.log4j.Logger; 
import com.facelook.entity.User; 
public class SessionListener implements HttpSessionListener{ 
private Logger logger = Logger.getLogger(this.getClass()); 
@Override 
public void sessionCreated(HttpSessionEvent event) { 
} 
@Override 
public void sessionDestroyed(HttpSessionEvent event) { 
//在session銷毀的時(shí)候 把loginUserMap中保存的鍵值對(duì)清除 
User user = (User)event.getSession().getAttribute("loginUser"); 
if(user!=null){ 
Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap"); 
loginUserMap.remove(user.getFuUserName()); 
event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap); 
} 
} 
}

web.xml中配置如下:

<!-- session listener --> 
<listener> 
<listener-class>com.facelook.util.SessionListener</listener-class> 
</listener>

3、另外,還有一個(gè)問題,如果說登錄的用戶突然關(guān)閉了瀏覽器或者頁面而沒有點(diǎn)擊退出按鈕。那么可以利用beforeunload 事件,在瀏覽器刷新或者關(guān)閉的時(shí)候觸發(fā)。

//在刷新或關(guān)閉時(shí)調(diào)用的事件 
$(window).bind('beforeunload',function(){ 
$.ajax({ 
url:"${ctx}/system/user/user!logout.action", 
type:"post", 
success:function(){ 
alert("您已退出登錄"); 
} 
}); 
);

但是如果一些客觀原因,比如電腦突然關(guān)機(jī),自動(dòng)重啟,等等,這些就沒法避免了,所以只能等待服務(wù)器端的session會(huì)話重置之后才可以再登錄。

除非 做一個(gè) 統(tǒng)計(jì)所有在線人員的模塊,管理員在里面進(jìn)行在線人員的登錄登出的狀態(tài)管理,把那些有問題的登錄用戶直接銷毀掉。

接下來簡(jiǎn)單介紹下在線人員模塊的管理:

1、首先需要一個(gè)session監(jiān)聽器來監(jiān)聽所有的回話create的情況,這時(shí)候每次創(chuàng)建一個(gè)session就可以count+1 ,然后銷毀的時(shí)候count-1 ,另外還需要一個(gè)ServletContext的監(jiān)聽器來監(jiān)聽web應(yīng)用的生命周期,獲取servletContext對(duì)象,然后將在線人員總數(shù)統(tǒng)計(jì)出來存放進(jìn)去;

具體代碼如下:

package com.facelook.util; 
import java.util.Map; 
import javax.servlet.ServletContext; 
import javax.servlet.ServletContextEvent; 
import javax.servlet.ServletContextListener; 
import javax.servlet.http.HttpSessionEvent; 
import javax.servlet.http.HttpSessionListener; 
import org.apache.log4j.Logger; 
import com.facelook.entity.User; 
public class SessionListener implements HttpSessionListener,ServletContextListener{ 
private int count; 
private ServletContext servletContext = null; 
public SessionListener() { 
count = 0; 
} 
private Logger logger = Logger.getLogger(this.getClass()); 
@Override 
public void sessionCreated(HttpSessionEvent event) { 
count++; 
setContext(event); 
logger.info("***************the http session is created...***************"); 
} 
@Override 
public void sessionDestroyed(HttpSessionEvent event) { 
//在session銷毀的時(shí)候 把loginUserMap中保存的鍵值對(duì)清除 
User user = (User)event.getSession().getAttribute("loginUser"); 
if(user!=null){ 
Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap"); 
loginUserMap.remove(user.getFuUserName()); 
event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap); 
} 
count--; 
setContext(event); 
logger.info("***************the http session is destroyed...***************"); 
} 
public void setContext(HttpSessionEvent httpSessionEvent){ 
httpSessionEvent.getSession().getServletContext().setAttribute("online", count); 
} 
@Override 
public void contextDestroyed(ServletContextEvent servletcontextevent) { 
this.servletContext = null; 
logger.info("***************the servlet context is destroyed...***************"); 
} 
@Override 
public void contextInitialized(ServletContextEvent servletcontextevent) { 
this.servletContext = servletcontextevent.getServletContext(); 
logger.info("***************the servlet context is initialized...***************"); 
} 
}

2、在UserAction中創(chuàng)建管理在線用戶的模塊的方法,并且支持強(qiáng)制退出的功能;

/** * 退出登錄 
* @return 
* @throws ServletException 
* @throws IOException 
*/ 
public String logout() throws ServletException, IOException{ 
try { 
Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP); 
User user = (User) super.getSessionAttr(Constant.LOGIN_USER); 
super.removeAttribute(Constant.LOGIN_USER_MAP); 
loginUserMap.remove(user.getFuUserName()); 
super.setApplicationAttr(Constant.LOGIN_USER_MAP,loginUserMap); 
logger.info("退出登錄成功!"); 
} catch (Exception e) { 
e.printStackTrace(); 
logger.error("退出登錄失敗: "+e.getMessage()); 
} 
return INPUT; 
} 
/** 
* 在線用戶管理 
* @return 
*/ 
public String loginManager(){ 
return SUCCESS; 
} 
/** 
* 強(qiáng)制退出其他用戶 
* @return 
*/ 
public String logoutOther(){ 
try { 
String username = ServletActionContext.getRequest().getParameter("username"); 
Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP); 
if(username!=null && loginUserMap.containsKey(username)){ 
loginUserMap.remove(username); 
super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap); 
} 
} catch (Exception e) { 
e.printStackTrace(); 
logger.info("強(qiáng)制退出失敗: "+e.getMessage()); 
} 
return null; 
}

3、在管理頁面加載在線用戶的列表;

對(duì)應(yīng)的方法定義完畢之后,然后再在對(duì)應(yīng)的管理頁面添加在線列表,具體如下:

<%@page import="java.util.Map"%> 
<%@page import="java.util.Map.Entry"%> 
<%@ page language="java" pageEncoding="UTF-8" %> 
<%@ include file="/common/taglib.jsp" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>歡迎來到Facelook</title> 
<%@ include file="/common/resource.jsp" %> 
<script type="text/javascript"> 
<!-- 
//在刷新或關(guān)閉時(shí)調(diào)用的事件 
$(window).bind('beforeunload',function(){ 
$.ajax({ 
url:"${ctx}/system/user/user!logout.action", 
type:"post", 
success:function(){ 
alert("您已退出登錄"); 
} 
}); 
}); 
function logout(username){ 
if(username=="${sessionScope.loginUser.fuUserName}"){ 
alert("不允許退出自己賬號(hào)!"); 
return; 
} 
$.ajax({ 
url:"${ctx}/system/user/user!logoutOther.action?username="+username, 
type:"post", 
success:function(){ 
$("#tr"+username).hide(); 
var count = parseInt($("#count").html()); 
$("#count").html(count-1); 
alert("退出成功!"); 
} 
}); 
} 
//--> 
</script> 
</head> 
<body> 
<%@ include file="/common/header.jsp" %> 
<div id="main" class="wrap"> 
<%@ include file="/common/lefter.jsp" %> 
<div class="righter"> 
<div class="main"> 
<h2>登錄列表</h2> 
<% 
Map<String,String> map = (Map<String,String>)application.getAttribute("loginUserMap"); 
out.println("目前共有<font id='count'>"+map.size()+"</font>個(gè)用戶在線?。?); 
%> 
<table border="1" width="400"> 
<%for(Entry<String,String> m : map.entrySet()){%> 
<tr id="tr<%=m.getKey()%>"> 
<td> 
<%=m.getKey()%> 
</td> 
<td width="80"> 
<a href="javascript:logout('<%=m.getKey()%>')">強(qiáng)制退出</a> 
</td> 
</tr> 
<%}%> 
</table> 
</div> 
</div> 
</div> 
<%@ include file="/common/footer.jsp" %> 
<%@ include file="/common/message.jsp" %> 
</body> 
</html>

好了啟動(dòng)部署項(xiàng)目,然后啟動(dòng)服務(wù),進(jìn)入在線用戶管理模塊,簡(jiǎn)單效果如下圖:

需要注意的是:當(dāng)前登錄用戶 不允許強(qiáng)制退出自己的登錄信息。

這樣子,基本上可以實(shí)現(xiàn)防止多用戶登錄的案例了!

以上所述是小編給大家介紹的Java Web開發(fā)防止多用戶重復(fù)登錄的完美解決方案,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Spring Boot集成Quartz注入Spring管理的類的方法

    Spring Boot集成Quartz注入Spring管理的類的方法

    本篇文章主要介紹了Spring Boot集成Quartz注入Spring管理的類的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • Spring中的使用@Async異步調(diào)用方法

    Spring中的使用@Async異步調(diào)用方法

    這篇文章主要介紹了Spring中的使用@Async異步調(diào)用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java爬蟲jsoup解析HTML的工具學(xué)習(xí)

    java爬蟲jsoup解析HTML的工具學(xué)習(xí)

    jsoup是一個(gè)解析HTML的第三方j(luò)ava庫,它提供了一套非常方便的API,可使用DOM,CSS以及類jQuery的操作方法來取出和操作數(shù)據(jù),本文就來開始jsoup的使用學(xué)習(xí)
    2022-07-07
  • 提高開發(fā)效率Live?Templates使用技巧詳解

    提高開發(fā)效率Live?Templates使用技巧詳解

    這篇文章主要為大家介紹了提高開發(fā)效率Live?Templates使用技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Java 使用Calendar計(jì)算時(shí)間的示例代碼

    Java 使用Calendar計(jì)算時(shí)間的示例代碼

    這篇文章主要介紹了Java 使用Calendar計(jì)算時(shí)間的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Spring?RestTemplate遠(yuǎn)程調(diào)用過程

    Spring?RestTemplate遠(yuǎn)程調(diào)用過程

    這篇文章主要介紹了Spring?RestTemplate遠(yuǎn)程調(diào)用過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • SpringBoot無法識(shí)別bootstrap.yml小綠葉問題的解決辦法

    SpringBoot無法識(shí)別bootstrap.yml小綠葉問題的解決辦法

    一般單獨(dú)使用?Spring?Boot?時(shí),bootstrap.yml?文件一般是不會(huì)生效的,也就是沒有小綠葉圖標(biāo),本文給大家介紹了SpringBoot無法識(shí)別bootstrap.yml小綠葉問題的解決辦法,文中給出了兩種解決方案,需要的朋友可以參考下
    2024-07-07
  • Java?HashSet的Removals()方法注意事項(xiàng)

    Java?HashSet的Removals()方法注意事項(xiàng)

    這篇文章主要介紹了Java?HashSet的Removals()方法注意事項(xiàng),文章圍繞制主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06
  • 關(guān)于Java鎖性能提高(鎖升級(jí))機(jī)制的總結(jié)

    關(guān)于Java鎖性能提高(鎖升級(jí))機(jī)制的總結(jié)

    這篇文章主要介紹了關(guān)于Java鎖性能提高(鎖升級(jí))機(jī)制的總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Spring的@Validation和javax包下的@Valid區(qū)別以及自定義校驗(yàn)注解

    Spring的@Validation和javax包下的@Valid區(qū)別以及自定義校驗(yàn)注解

    這篇文章主要介紹了Spring的@Validation和javax包下的@Valid區(qū)別以及自定義校驗(yàn)注解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評(píng)論

岐山县| 洪雅县| 当阳市| 泰顺县| 肥西县| 孟津县| 贵溪市| 屏山县| 永安市| 抚顺市| 巴青县| 金乡县| 泰顺县| 安乡县| 佳木斯市| 运城市| 周至县| 伊宁市| 新余市| 德昌县| 华池县| 威宁| 泰来县| 沙洋县| 昌邑市| 普安县| 罗平县| 合江县| 志丹县| 察雅县| 惠水县| 芜湖县| 玛沁县| 新河县| 沙河市| 邵阳市| 万州区| 错那县| 平陆县| 璧山县| 阜平县|