项目实战--网页五子棋(匹配模块)(4)
上期我们完成了游戏大厅的前端部分内容,今天我们实现后端部分内容
1. 维护在线用户
在用户登录成功后,我们可以维护好用户的websocket会话,把用户表示为在线状态,方便获取到用户的websocket会话
package org.ting.j20250110_gobang.game;import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;import java.util.HashMap;
import java.util.Map;@Component
public class OnlineUserManager {//使用ConcurrentHashMap保证线程安全private Map<Integer, WebSocketSession> onlineUser = new ConcurrentHashMap<>();public void enterGameHall(int userId, WebSocketSession session) {//用户上线onlineUser.put(userId, session);}public void exitGameHall(int userId) {//用户下线onlineUser.remove(userId);}public WebSocketSession getFromHall(int userId) {//获取用户的websocket会话return onlineUser.get(userId);}
}
这里我们借助一个哈希表就可以实现。
2. 实现webSocket相关方法
上期我们定义了webSocket的处理类,但是并没有完成重写的方法,接下来我们借助维护的在线用户具体实现如下方法

在实现这些方法之前,我们还需要按照上期约定好的信息交互形式定义两个实体类,代表请求和响应:
package org.ting.j20250110_gobang.game;public class MatchRequest {private String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
package org.ting.j20250110_gobang.game;public class MatchResponse {private boolean ok;private String errMsg;private String message;public boolean isOk() {return ok;}public void setOk(boolean ok) {this.ok = ok;}public String getErrMsg() {return errMsg;}public void setErrMsg(String errMsg) {this.errMsg = errMsg;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
2.1 连接成功
//连接成功后执行@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {//玩家上线try {//获取登录时储存在session中的用户信息,这里WebSocketSession在注册时通过拦截器获取到了session中的内容User user = (User)session.getAttributes().get("user");if(onlineUser.getFromHall(user.getId()) == null) {onlineUser.enterGameHall(user.getId(), session);System.out.println("用户:" + user.getUsername() + " 已上线");}else{//防止重复登录MatchResponse response = new MatchResponse();response.setOk(false);response.setErrMsg("用户已在别处登录");session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));session.close();}}catch (NullPointerException e) {e.printStackTrace();MatchResponse response = new MatchResponse();response.setOk(false);response.setErrMsg("用户未登录");session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));}}
2.2 连接断开
//连接异常时执行@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {//连接异常断开,玩家下线try {User user = (User)session.getAttributes().get("user");//防止重复登录时删除正常登录的在线信息if(onlineUser.getFromHall(user.getId()).equals(session)) {onlineUser.exitGameHall(user.getId());System.out.println("用户:" + user.getUsername() + " 已下线");}}catch (NullPointerException e) {e.printStackTrace();MatchResponse response = new MatchResponse();response.setOk(false);response.setErrMsg("用户未登录");session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));}}//连接正常断开后执行@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {//连接正常断开,玩家下线try {User user = (User)session.getAttributes().get("user");//防止重复登录时删除正常登录的在线信息if(onlineUser.getFromHall(user.getId()).equals(session)) {onlineUser.exitGameHall(user.getId());System.out.println("用户:" + user.getUsername() + " 已下线");}}catch (NullPointerException e) {e.printStackTrace();MatchResponse response = new MatchResponse();response.setOk(false);response.setErrMsg("用户未登录");session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));}}
2.3 处理匹配请求
//接收到请求后执行@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {User user = (User) session.getAttributes().get("user");MatchRequest request = objectMapper.readValue(message.getPayload(), MatchRequest.class);MatchResponse response = new MatchResponse();if(request.getMessage().equals("startMatch")) {//开始匹配,把用户加入匹配队列//todoresponse.setOk(true);response.setMessage("startMatch");}else if(request.getMessage().equals("stopMatch")) {//取消匹配,从匹配队列中移除用户//todoresponse.setOk(true);response.setMessage("stopMatch");}else{response.setOk(false);response.setErrMsg("非法请求");}}
这里=具体的匹配队列功能我们下期再实现
相关文章:
项目实战--网页五子棋(匹配模块)(4)
上期我们完成了游戏大厅的前端部分内容,今天我们实现后端部分内容 1. 维护在线用户 在用户登录成功后,我们可以维护好用户的websocket会话,把用户表示为在线状态,方便获取到用户的websocket会话 package org.ting.j20250110_g…...
P8716 [蓝桥杯 2020 省 AB2] 回文日期
1 题目说明 2 题目分析 暴力不会超时,O(n)的时间复杂度, < 1 0 8 <10^8 <108。分析见代码: #include<iostream> #include<string> using namespace std;int m[13]{0,31,28,31,30,31,30,31,31,30,31,30,31};// 判断日期…...
如何在视频中提取关键帧?
在视频处理中,提取关键帧是一项常见的任务。下面将介绍如何基于FFmpeg和Python,结合OpenCV库来实现从视频中提取关键帧的功能。 实现思路 使用FFmpeg获取视频的关键帧时间戳:FFmpeg是一个强大的视频处理工具,可以通过命令行获取…...
為什麼使用不限量動態住宅IP採集數據?
在瞭解“不限量動態住宅IP數據採集”之前,我們需要先搞清楚什麼是“動態住宅IP”。簡單來說,動態IP是一種會定期變化的IP地址,通常由互聯網服務提供商(ISP)分配給家庭用戶。與固定IP(靜態IP)不同…...
Go语言中使用viper绑定结构体和yaml文件信息时,标签的使用
在Go中使用Viper将YAML配置绑定到结构体时,主要依赖 mapstructure 标签(而非 json 或 yaml 标签)实现字段名映射。 --- ### 1. **基础绑定方法** 使用 viper.Unmarshal(&config) 或 viper.UnmarshalKey("key", &subConfi…...
OpenIPC开源FPV之Adaptive-Link安装
OpenIPC开源FPV之Adaptive-Link安装 1. 源由2. 介绍2.1 天空端安装2.2 地面端安装 3. 问题汇总3.1 安装脚本问题3.2 网络安装问题3.3 非SSC30KQ/SSC338Q硬件3.4 代码疑问 4. 总结5. 后续 1. 源由 鉴于飞行过程,发现一些马赛克现象,且60FPS桌面30FPS的录…...
[杂学笔记]OSI七层模型作用、HTTP协议中的各种方法、HTTP的头部字段、TLS握手、指针与引用的使用场景、零拷贝技术
1.OSI七层模型作用 物理层:负责光电信号的传输,以及将光电信号转化为二进制数据数据链路层:主要负责将收到的二进制数据进一步的封装为数据帧报文。同时因为数据在网络中传递的时候,每一个主机都能够收到报文数据,该层…...
RK3568开发笔记-AD7616调试笔记
目录 前言 一、AD7616介绍 高分辨率 高速采样速率 宽模拟输入范围 集成丰富功能 二、原理图连接 三、设备树配置 四、内核驱动配置 五、AD芯片测试 总结 前言 在嵌入式数据采集领域,将模拟信号精准转换为数字信号至关重要。AD7616 作为一款性能卓越的 16 位模数转换器…...
Unity摄像机与灯光相关知识
一、Inspector窗口 Inspector窗口可以查看和编辑对象的属性以及设置 其中包含各种组件,例如用Cube对象来举例 1.Sphere(Mesh)组件: 用来决定对象的网格属性,例如球体网格为Sphere、立方体网格为Cube 2.Mesh Renderer组件: 用来设置…...
AI前端革新金融风控:ScriptEcho助力高效开发
1. 引言:金融风控的挑战与前端效率需求 在当今快速变化的金融环境中,风险评估和反欺诈已成为金融机构运营的核心。金融风控不仅关乎企业的盈利能力,更直接影响着整个金融体系的稳定。一个强大的风控系统需要能够实时监控、分析并预测潜在的风…...
STM32--SPI通信讲解
前言 嘿,小伙伴们!今天咱们来聊聊STM32的SPI通信。SPI(Serial Peripheral Interface)是一种超常用的串行通信协议,特别适合微控制器和各种外设(比如传感器、存储器、显示屏)之间的通信。如果你…...
CryptoJS库中WordArray对象支持哪些输出格式?除了toString() 方法还有什么方法可以输出吗?WordArray对象的作用是什么?
前言:这里只说js用的CryptoJS库里的相关内容,只用js来进行代码操作和讲解。 这里网上相关的帖子很少,不得已问了很长时间AI 想引用CryptoJS库情况分两种,一种是html引用,另一种是在Nodejs里引用。 一、引用CryptoJS库…...
第六次作业
一.对比 LVS 负载均衡群集的 NAT 模式和 DR 模式,比较其各自的优势 。 LVS-NAT模式的优势 配置简单:NAT模式的配置相对容易,无需复杂的网络设置,适合初学者和小型网络环境。 网络架构灵活:由于使用了NAT技术…...
八、Spring Boot:RESTful API 应用
创建第一个 Spring Boot RESTful API 应用 在现代 Web 开发中,RESTful API 是一种非常流行的设计风格,它基于 HTTP 协议,提供了简单、灵活的方式来构建网络应用。Spring Boot 作为一款强大的微服务框架,提供了丰富的工具和支持&a…...
Pytorch实现之混合成员GAN训练自己的数据集
简介 简介:提出一种新的MMGAN架构,使用常见生成器分布的混合对每个数据分布进行建模。由于生成器在多个真实数据分布之间共享,高度共享的生成器(通过混合权重反映)捕获分布的公共方面,而非共享的生成器捕获独特方面。 论文题目:MIXED MEMBERSHIP GENERATIVE ADVERSARI…...
微信小程序网络请求与API调用:实现数据交互
在前几篇文章中,我们学习了微信小程序的基础知识、数据绑定、事件处理以及页面导航与路由。这些知识帮助我们构建了具备基本交互功能的小程序。然而,一个完整的应用通常需要与服务器进行数据交互,例如获取用户信息、提交表单数据等。本文将深入探讨微信小程序的网络请求与AP…...
Cramér-Rao界:参数估计精度的“理论底线”
Cramr-Rao界:参数估计精度的“理论底线” 在统计学中,当我们用数据估计一个模型的参数时,总希望估计结果尽可能精确。但精度有没有一个理论上的“底线”呢?答案是有的,这就是Cramr-Rao界(Cramr-Rao Lower …...
nv docker image 下载与使用命令备忘
1,系统需求 Requirements for GPU Simulation GPU Architectures Volta, Turing, Ampere, Ada, Hopper NVIDIA GPU with Compute Capability 7.0 CUDA 11.x (Driver 470.57.02), 12.x (Driver 525.60.13) Supported Systems CPU architectures x86_64, ARM…...
C#连接sql server
连接时,出现如下提示: ERROR [IM014] [Microsoft][ODBC 驱动程序管理器] 在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配 原因是odbc的驱动和应用程序的架构不一致。我的odbc如下所示: 显示为64位,而c#程序显…...
汽车智能制造企业数字化转型SAP解决方案总结
一、项目实施概述 项目阶段划分: 蓝图设计阶段主数据管理方案各模块蓝图设计方案下一阶段工作计划 关键里程碑: 2022年6月6日:项目启动会2022年12月1日:系统上线 二、总体目标 通过SAP实施,构建研产供销协同、业财一…...
【JavaScript高级编程】拆解函数流水线 上加
一、什么是setuptools? setuptools 是一个用于创建、分发和安装 Python 包的核心库。 它可以帮助你: 定义 Python 包的元数据(如名称、版本、作者等)。 声明包的依赖项,确保你的包能够正确运行。 构建源代码分发包&…...
ATAC-seq 实战指南:从BAM到TSS富集热图的完整流程解析
1. ATAC-seq分析入门:从BAM文件到TSS富集热图全流程 ATAC-seq(Assay for Transposase-Accessible Chromatin using sequencing)作为研究染色质开放性的重要技术,已经成为表观遗传学领域的标配工具。对于刚拿到测序数据的生物信息学…...
别再只跑Demo了!把YOLOv5部署到‘真实’场景:FPS游戏画面实时目标检测的完整实践与踩坑记录
从Demo到实战:YOLOv5在FPS游戏实时目标检测中的工程化实践 当你第一次看到YOLOv5在COCO数据集上跑出漂亮的检测结果时,是否也曾想过把它应用到更有趣的场景?比如,让AI帮你"看"懂FPS游戏画面。但真正动手后才发现&#…...
网络工程师-网络规划与设计(一):网络开发过程与逻辑网络设计
一、引言1.1 核心概念定义网络规划与设计是将业务需求转化为可落地网络技术方案的系统工程,覆盖从需求调研到运维优化的全生命周期,是网络可靠性、可扩展性、安全性的核心保障。在软考网络工程师考试中,本章节属于网络系统设计与管理模块&…...
Safe Stable - 高效安全的Ckpt2Safetensors模型转换工具
Safe & Stable - 高效安全的Ckpt2Safetensors模型转换工具 【免费下载链接】Safe-and-Stable-Ckpt2Safetensors-Conversion-Tool-GUI Convert your Stable Diffusion checkpoints quickly and easily. 项目地址: https://gitcode.com/gh_mirrors/sa/Safe-and-Stable-Ckpt…...
终极指南:如何快速解决RevokeMsgPatcher微信3.9.10.19版本路径兼容性问题
终极指南:如何快速解决RevokeMsgPatcher微信3.9.10.19版本路径兼容性问题 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: …...
Nat Neurosci:当神经元“自己选图”——灵长类视觉系统如何在纹理与物体之间动态寻找最优表征
视觉神经元究竟“喜欢”什么样的图像?这个问题看似简单,却困扰了视觉神经科学几十年。对于初级视觉皮层(V1)的神经元,我们已经知道它们偏好边缘、方向、空间频率等较为简单的特征;但越往高级视觉区域走&…...
【macOS】精选效率神器!大幅提升办公速度的宝藏软件
目录 01 文本编辑 1.1 Notable 1.2 MarkEdit01 文本编辑 1.1 Notable 🌸 开源轻量化 Markdown 笔记,主打数据可控。 🌸 支持多系统:Linux, Windows, macOS。 🌺 网址为:https://notable.app/ 1.2 MarkEdi…...
告别Transformer的O(L²)噩梦:手把手教你用Informer搞定超长时序预测(附PyTorch避坑指南)
Informer:突破Transformer长序列预测的极限实战指南 当电力调度系统需要预测未来一周的负荷曲线,或是云服务商要预估下个月服务器流量峰值时,传统时序模型往往力不从心。这类超长序列预测任务(LSTF)要求模型既能捕捉跨…...
7个Masa模组中文汉化包:让Minecraft说中文的终极指南
7个Masa模组中文汉化包:让Minecraft说中文的终极指南 【免费下载链接】masa-mods-chinese 一个masa mods的汉化资源包 项目地址: https://gitcode.com/gh_mirrors/ma/masa-mods-chinese 还在为Minecraft中那些强大的Masa系列模组全是英文界面而头疼吗&#x…...
