一,仿QQ異地登錄強制下線功能
效果:同一個賬號,最後一個登錄的用戶會把前一個登錄後的用戶頂掉,被迫下線!
1,剖析登錄原理
登錄的後臺邏輯
- 準備一張賬戶信息表(賬號,密碼,是否禁用等字段)
- 查詢賬號密碼,如果正確就記錄
session
,並重定向到首頁。
而實現上述效果只需要稍加修改即可。
- 第一處修改,在賬戶信息表後新增一個字段,存儲登錄用戶的
sessionId
的值。 - 第二處修改,在登錄時,查詢賬號密碼正確並重定向到首頁之前添加一個步驟,就是更新當前賬號對應的
sessionId
字段。(不同瀏覽器的sessionId
都是唯一的) - 退出時,在清除
session
之前,把當前賬號對應的sessionId
字段值置Null
。 - 寫一個輪詢方法,根據當前瀏覽器的
sessionId
到賬戶信息表查詢是否可以查到,如果查得到,說明賬號狀態正常,如果沒有查到,只能是該賬號被另一個瀏覽器進行訪問登錄了(會覆蓋掉原來的sessionId
,改爲登錄人本機瀏覽器的sessionId
)
2,數據庫表設計
3,代碼實現
登錄請求方法
/**
* todo 登錄請求
*/
@PostMapping("/loginSubmit")
public String loginSubmit(String username, String password, HttpSession session, Model model){
List<Map> accountByPassword = busineService.getAccountByPassword(username, password);
if(accountByPassword.size()>0){
//用戶存在
session.setAttribute("account",username);
model.addAttribute("account",username);
//############## 重點 #########################
String sessionid = session.getId();
int i = busineMapper.updateSessionIdByUsername(sessionid, username);
//############## 重點 #########################
return "redirect:/business/index";
}else{
//用戶不存在
model.addAttribute("msg","用戶名或密碼錯誤");
return "login";
}
}
退出登錄方法
/**
* todo 退出系統
*/
@RequestMapping("/logout")
public String logout(HttpSession session){
String username=(String) session.getAttribute("account");
//############## 重點 #########################
int i = busineMapper.updateSessionIdByUsername(null, username);
//############## 重點 #########################
session.removeAttribute("account");
return "forward:/business/login";
}
/**
* todo 退出系統[通知下線時點擊確定跳轉此方法,不可以清空sessionId的值,因爲後來登錄的人要正常使用系統]
*/
@RequestMapping("/logout1")
public String logout1(HttpSession session){
session.removeAttribute("account");
return "forward:/business/login";
}
登錄sql實現
// todo 登錄
@Select(value = "select * from activiti_account where username=#{username} and password=#{password} and yxbz=1")
List<Map> getAccountByPassword(@Param("username") String username, @Param("password") String password);
//登錄時更新賬號表的sessionid字段
@Update(value = "update activiti_account set sessionid=#{sessionid} where username=#{username}")
int updateSessionIdByUsername(@Param("sessionid") String sessionid,@Param("username") String username);
//輪詢檢查sessionid是否存在或是否被替換
@Select(value = "select * from activiti_account where sessionid=#{sessionid}")
Map checkSessionId(String sessionid);
js
寫一個定時器,定時刷新賬號登錄狀態
$(function () {
var is=true;
setInterval(function () {
if(is){
$.ajax({
url:"/business/checkSessionId",
type:"post",
dataType:"json",
success:function (data) {
if(data==0){
is=false;
layer.confirm('您的賬號已在異地登錄,請重新登錄', {
btn: ['確定'] //按鈕
}, function(){
//退出並跳轉登錄頁面
window.location.href = "/business/logout1";
}, function(){
//退出並跳轉登錄頁面
window.location.href = "/business/logout1";
});
}
}
});
}
},5000);
輪詢方法
//輪詢檢查sesiosnid是否被替換,如果被替換,說明該賬號已在異地登錄
@RequestMapping("/checkSessionId")
@ResponseBody
public int checkSessionId(HttpSession session){
Map map = busineMapper.checkSessionId(session.getId());
if(map!=null){
//沒有被替換,賬號狀態正常
return 1;
}else{
//賬號已在異地登錄,掉線通知
return 0;
}
}
效果截圖
二,仿淘寶吱口令的功能實現
效果:在A平臺上覆制一段某商品分享的吱口令,然後打開B平臺,然後B平臺會自動識別用戶複製的吱口令,並打開該口令對應商品的詳情頁。
步驟分析:
- 在A平臺封裝某商品的詳情信息包括頁面鏈接,然後加密處理,生成一段字符串,供用戶複製。
- 打開B平臺,B平臺監聽剪切板中的吱口令信息,【監聽方式使用
JS
定時器請求後臺方法,該方法到剪切板中查看吱口令內容】,如果有吱口令信息,則解密吱口令並打開該口令對應商品的詳情頁。
這裏沒有具體實現,只給出實現思路,不過實現起來挺簡單的!
剪切板如何操作?
Java 操作剪貼板的類在 java.awt.* 包(及其子包)下,獲取系統剪貼板代碼
下面代碼實現用 Java
代碼獲取系統剪貼板對象,實現 複製 和 粘貼 文本的例子。
package com.xiets.clipboard;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
public class Main {
public static void main(String[] args) throws InterruptedException {
// 把文本設置到剪貼板(複製)
setClipboardString("Hello System Clipboard!");
// 從剪貼板中獲取文本(粘貼)
String text = getClipboardString();
System.out.println("text: " + text);
}
/**
* 把文本設置到剪貼板(複製)
*/
public static void setClipboardString(String text) {
// 獲取系統剪貼板
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
// 封裝文本內容
Transferable trans = new StringSelection(text);
// 把文本內容設置到系統剪貼板
clipboard.setContents(trans, null);
}
/**
* 從剪貼板中獲取文本(粘貼)
*/
public static String getClipboardString() {
// 獲取系統剪貼板
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
// 獲取剪貼板中的內容
Transferable trans = clipboard.getContents(null);
if (trans != null) {
// 判斷剪貼板中的內容是否支持文本
if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
// 獲取剪貼板中的文本內容
String text = (String) trans.getTransferData(DataFlavor.stringFlavor);
return text;
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
}
控制檯輸出
參考文章:https://blog.csdn.net/xietansheng/article/details/70478266