版權所有:(xiaodaoxiaodao)藍小刀
http://www.aygfsteel.com/xiaodaoxiaodao/archive/2007/06/16/124692.html
?
轉載請注明來源/作者
一個帳號同一時間只能一個人登錄
對于一個帳號在同一時間只能一個人登錄,可以通過下面的方法實現:
1
.在用戶登錄時,把用戶添加到一個ArrayList中
2
.再次登錄時查看ArrayList中有沒有該用戶,如果ArrayList中已經存在該用戶,則阻止其登錄
3
.當用戶退出時,需要從該ArrayList中刪除該用戶,這又分為三種情況
①
使用注銷按鈕正常退出
②
點擊瀏覽器關閉按鈕或者用Alt+F4退出,可以用javascript捕捉該頁面關閉事件,
執行一段java方法刪除ArrayList中的用戶
③
非正常退出,比如客戶端系統崩潰或突然死機,可以采用隔一段時間session沒活動就刪除該session所對應的用戶來解決,這樣用戶需要等待一段時間之后就可以正常登錄。
在LoginAction中定義:
//
用來在服務器端存儲登錄的所有帳號
public static List logonAccounts;
login()
登錄方法中:
//
設置session不活動時間為30分
request.getSession().setMaxInactiveInterval(60*30);
if(logonAccounts==null){
??? logonAccounts = new ArrayList();
}
//
查看ArrayList中有沒有該用戶
for (int i = 0; i < logonAccounts.size(); i++) {
??? Account existAccount = (Account)logonAccounts.get(i);
??? if(account.getAccountId().equals(existAccount.getAccountId())){
??????? return "denied";
??? }
}
//
在用戶登錄時,把sessionId添加到一個account對象中
//
在后面
③
需要根據此sessionId刪除相應用戶
account.setSessionId(request.getSession().getId());
//
該用戶保存到ArrayList靜態類變量中
logonAccounts.add(account);
return "login";
①
使用注銷按鈕正常退出
logout()
退出方法中:
if(logonAccounts==null){
??? logonAccounts = new ArrayList();
}
//
刪除ArrayList中的用戶
?⑴
for (int i = 0; i < logonAccounts.size(); i++) {
??? Account existAccount = (Account)logonAccounts.get(i);
??? if(account.getAccountId().equals(existAccount.getAccountId())){
??????? logonAccounts.remove(account);
??? }
}
②
點擊瀏覽器關閉按鈕或者用Alt+F4退出:
在后臺彈出一個窗口,在彈出窗口中刪除ArrayList中的用戶
function window.onbeforeunload(){
//
是否通過關閉按鈕或者用Alt+F4退出
//
如果為刷新觸發onbeforeunload事件,下面if語句不執行
??? if (event.clientX>document.body.clientWidth && event.clientY<0||event.altKey){
??????? window.open('accountUnbound.jsp','',
??????????????? 'height=0,width=0,top=10000,left=10000')
??? }
}
accountUnbound.jsp
:
彈出窗口中刪除ArrayList中的用戶
<%
??
?Account account = (Account) request.getSession().getAttribute("account");
??? if(account != null){
??????? if(LoginAction.logonAccounts==null){
??????????? LoginAction.logonAccounts = new ArrayList();
??????? }
???????
//
刪除ArrayList中的用戶——下面代碼和上面的
⑴
處一樣
??????? for (int i = 0; i < logonAccounts.size(); i++) {
??????????? Account existAccount = (Account)logonAccounts.get(i);
??????????? if(account.getAccountId().equals(existAccount.getAccountId())){
??????????????? logonAccounts.remove(account);
??????????? }
??????? }
??
?}
%>
為了保證上面代碼可以執行完畢,3秒后關閉此彈出窗口(也位于accountUnbound.jsp中)
<script>
setTimeout("closeWindow();",3000);
function closeWindow(){
??? window.close();
}
</script>
③
使LoginAction 實現implements HttpSessionListener,并實現sessionCreated,sessionDestroyed方法,在sessionDestroyed中刪除ArrayList中的用戶(用戶超過30分鐘不活動則執行此方法)
public void sessionDestroyed(HttpSessionEvent event) {
??
//
取得不活動時的sessionId,并根據其刪除相應logonAccounts中的用戶
?? String sessionId = event.getSession().getId();
?? for (int i = 0; i < logonAccounts.size(); i++) {
?????? Account existAccount = (Account)logonAccounts.get(i);
?????? if(account.getSessionId().equals(existAccount.getSessionId())){
?????????? logonAccounts.remove(account);
?????? }
?? }
}
注:
對于上面的,由于彈出窗口很容易被防火墻或者安全軟件阻攔,造成無法彈出窗口,從而短時間不能登錄,這種情況可以用AJAX來代替彈出窗口,同樣在后臺執行刪除用戶的那段代碼,卻不會受到防火墻限制:
<script>
??? // <![CDATA[
??? var http_request = false;
??? function makeRequest(url) {
??????? http_request = false;
??????? if (window.XMLHttpRequest) { // Mozilla, Safari,...
??????????? http_request = new XMLHttpRequest();
??????????? if (http_request.overrideMimeType) {
??????????????? http_request.overrideMimeType('text/xml');
??????????? }
??????? } else if (window.ActiveXObject) { // IE
??????????? try {
?????????????
??http_request = new ActiveXObject("Msxml2.XMLHTTP");
??????????? } catch (e) {
??????????????? try {
??????????????????? http_request = new ActiveXObject("Microsoft.XMLHTTP");
??????????????? } catch (e) {
??????????????? }
??????????? }
??????? }
??????
?if (!http_request) {
??????????? alert('Giving up :( Cannot create an XMLHTTP instance');
??????????? return false;
??????? }
??????? http_request.onreadystatechange = alertContents;
??????? http_request.open('GET', url, true);
??????? http_request.send(null);
??? }
??? function alertContents() {
??????? if (http_request.readyState == 4) {
??????????? if (http_request.status == 200) {
??????????????? window.close();
??????????? } else {
??????????????? alert('There was a problem with the request.');
????
???????}
??????? }
??? }
??? function window.
onbeforeunload()
{
???????
makeRequest
('accountUnbound.jsp');
??? }
??? //]]>
</script>
對于上面的這段ajax代碼,在網上有很多詳細的解釋,把它加到onbeforeunload()瀏覽器關閉事件中,在后臺執行代碼的效果很好,不必擔心彈出窗口有時候會無效的問題。
使用這段代碼后,上面②中accountUnbound.jsp中的那段關閉彈出窗口window.close();的js代碼就不需要了。
版權所有:(xiaodaoxiaodao)藍小刀
??
xiaodaoxiaodao@gmail.com
在Person領域對象中加一個boolean型的對象active,用來標志用戶是否已經登錄即可,何必這么麻煩.
這么會有這種人。。。
請注意素質。。
支持
應該做成這樣
請教兩個問題:
1.
function window.onbeforeunload(){
window.open('accountUnbound.jsp','',
'height=0,width=0,top=10000,left=10000')
}
這個函數是需要放在哪個頁面里呢?
2.讓哪個類來實現HttpSessionListener接口呢?還是隨便創建一個類就可以呢?
多謝~!
理論上是應該后面登錄的人踢出前面的人,然后前面的人被踢出時會有一個提示信息,這樣做法比較符合用戶習慣~
上面的做法其實是為了應付我這個項目客戶的需求,客戶要求這么做~
不知道和此人有何過節,剛去逛街回來,心情還好~
onbeforeunload()方法放在你的主頁面中,比如對于B/S結構的項目,經常會有一個html中frameset的結構,里面定義了一些frame,例如這樣:
<frameset id="frameset" rows="*" cols="170,*,170">
<frame src="left.jsp" name="left" id="left"/>
<frame src="main.jsp" name="main" id="main"/>
<frame src="right.jsp" name="right" id="right"/>
</frameset>
這時可以把onbeforeunload()方法放在這個頁面中~~
總之,就是這個頁面一定滿足:無論你在瀏覽器中怎么跳轉,點擊瀏覽器關閉按鈕,這個頁面一定會被卸載,這樣才能保證onbeforeunload()方法一定會執行~
2.
讓哪個類來實現HttpSessionListener接口呢?
理論上哪個類都可以,不過為了邏輯上的清楚,最好選取一個相關類比如LoginAction或者Account來實現,也可以定義一個專門的類同時把logonAccounts這個靜態變量也放入其中~~
注意當類A實現HttpSessionListener接口時,必須在web.xml中配置:
<listener>
<listener-class>A</listener-class>
</listener>
這時就出現用戶刷新頁面,系統就將該用戶踢出的問題
這時該怎么解決?
function window.onbeforeunload(){
// 是否通過關閉按鈕或者用Alt+F4退出
// 如果為刷新觸發onbeforeunload事件,下面if語句不執行
if (event.clientX>document.body.clientWidth && event.clientY<0||event.altKey){
window.open('accountUnbound.jsp','',
'height=0,width=0,top=10000,left=10000')
}
}
汗…… 我個人不懂分布式應用的,從來沒有接觸過,現在也不太了解這個概念~~
function window.onbeforeunload(){
// 是否通過關閉按鈕或者用Alt+F4退出
// 如果為刷新觸發onbeforeunload事件,下面if語句不執行
if (event.clientX>document.body.clientWidth && event.clientY<0||event.altKey){
window.open('accountUnbound.jsp','',
'height=0,width=0,top=10000,left=10000')
}
}
這個判斷方法我測試過,在IE7中無效;IE6中是可以的。
將用戶狀態信息保存到數據庫,就可以實現分布式了吧?
IE7我這邊暫時不方便測試,不過google到了一種辦法http://bbs.51js.com/viewthread.php?tid=67863 ,你可以參考一下~~
這個方法我剛剛在IE6下測試過沒有問題,不知道IE7如何~~
要在關閉窗口時觸發一個事件,我們會想到window對象提供了兩個事件:onUnload和onBerforUnload,因為它們是針對document的,當document被卸載或被卸載前觸發。但這兩個事件在刷新時也會觸發,所以我們要采用什么方法來屏蔽除了關閉窗口操作以外而觸發的onUnload和onBerforUnload事件從而執行里面的操作呢? 下面是從網上搜到的和大家一起分享。
<script>
window.onunload = function(){if(self.screenTop>9000)alert('該窗口已經被關閉!')}
</script>
或
<script>
window.onunload = function(){if(self.screenLeft>9000)alert(該窗口已經被關閉!.')}
</script>
下面是對這兩個window的屬性的解釋:
window.screenTop
獲取瀏覽器客戶區左上角相對于屏幕左上角的 y 坐標
screenTop>后面的數字必須大于你顯示分辯率中的高度
比如,800*600, 這個數得大于600
window.screenLeft
獲取瀏覽器客戶區左上角相對于屏幕左上角的 x 坐標
screenLeft>后面的數字必須大于你顯示分辯率中的寬度
比如,800*600, 這個數得大于800
通常這兩個值設為9000
還好這個還沒被封,大家還可以去看看,web2.0的IT速查手冊。地址是:http://wopingit.com/
此信息從這里獲得(http://wopingit.blog.sohu.com/53904073.html)。
看我的吧
public static List logonAccounts;
public static Set logonAccounts;