仿QQ异地登录被迫下线功能的实现
一,仿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
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~