Springboot项目——网页版本五子棋

news2024/11/18 2:48:15

网页五子棋:项目简单实现了网页版本的五子棋对战功能,同时会根据用户的天梯分数来匹配,可供多位用户同时提供对战功能。大致可分为三个模块,用户模块,匹配模块,对战模块,下面重点介绍以下三个模块。

101.42.44.62:10010/login.html

一、全局处理

1. 拦截器

1)自定义拦截器类实现 HandlerInterceptor 接口,重写 preHandle 方法,用于拦截未登录用户的请求。

2)自定义配置类实现 WebSocketConfigurer 接口,重写 registerWebSocketHandlers 方法,用于注册后续重写 TextWebSocketHandler 的类,使得后续客户端和服务端的通信能正确进行,同时为该配置类加上 @EnableWebSocket 注解,使得 Spring 知道该类是 WebSocket 的配置类;实现 WebMvcConfigurer  接口,重写 addInterceptors 方法,表示对哪些请求进行拦截。

2. 统一数据格式返回

1)自定义结果实体类 Result,其属性包括 code(业务码),errMsg(错误信息),data(接口响应的数据,泛型);其静态方法有 success(T data),在请求成功时可调用,参数 data,表示给前端返回的数据内容;fail(String errMsg),在请求非法时可调用,参数 errMsg,表示非法请求的错误信息。其中,Result 类中的属性 code 通过自定义枚举类来实现,保证 code 值的正确性。        

2)自定义响应通知类,实现 ResponseBodyAdvice 接口,并重写其 supports 方法和 beforeBodyWrite 方法,supports 方法:判断是否要执行 beforeBodyWrite 方法,true 为执行,false不执行;beforeBodyWrite 方法:对response方法进行的具体操作处理,如果返回的结果已经是Result类时,需直接返回,另外,如果返回的结果时 String类型,需通过 ObjectMapper 进行特殊处理。

 二、用户模块

通过 UserController 类实现

1. 登录

1)前端页面

2)后端实现 

使用 JWT 令牌(Json Web Token)存储用户登录信息,同时将 user 对象存储在 Session 中,方便后续使用WebSocketSession 获取到用户信息;后端首先校验用户信息的合法性,当校验成功时,为该用户生成令牌,服务器将用户的用户名存储在 token 中(方便后续获取用户信息),并设置过期时间,客户端将令牌存储在浏览器的 Local Storage 中,并将 token 设置在请求头 Header 中,后续客户端的请求都会带着 token,服务器会校验令牌,来决定是否拦截用户的请求。

2. 注册

1)前端页面

2)后端实现 

使用 MD5 算法加密、UUID 加盐共同加密用户的密码,保证用户密码的安全性。服务器首先判断用户注册信息的合法性,用户名不能重复,两次密码需输入一致等;判断合法后,将用户的密码和UUID 生成的随机盐值,使用 MD5 算法进行加密后,存储在数据库中。

3. 获取用户信息

服务器从请求头 Header 中获取到 token,并获取到存储在 token 中的用户名,根据用户名在数据库中查询相应的用户信息并返回。

三、model类

1. 用户类 User

其属性包括 int userId 用户 id,String username 用户名,String password 密码,int score 天梯分数,int totalCount 总场数,int winCount 获胜场数;

2. 自定义匹配请求实体类 MatchRequest

其属性包括 String message,表示请求内容;

3. 自定义匹配响应实体类 MatchResponse

其属性包括 boolean ok,表示响应的状态,String reason,表示响应状态错误时的错误原因,String message,表示响应内容;

4. 自定义游戏就绪响应类 GameReadyResponse

因为在服务器确认游戏匹配成功后,此时直接就向客户端发送游戏就绪响应,不需要游戏就去请求;其属性包括:String message 响应信息,boolean ok 响应状态,String reason 失败时的原因,String roomId 游戏房间 id,int thisUserId 玩家 1 的 id,int thatUserId 玩家 2 的 id,int blackUser 执黑子的玩家 id;

5. 自定义游戏请求类 GameRequest

用来表示一次游戏请求(即落子请求),其属性包括 String message 请求信息,int userId 落子玩家,int row 落子的行数,int col 落子的列数;

6. 自定义游戏响应类 GameResponse

用来表示一次游戏响应(即落子响应),其属性包括 String message 响应信息,int userId 响应返回的玩家,int row 落子的行数,int col 落子的列数(由于需要实时的将棋盘上的信息反馈给每个玩家),int winner 表示获胜方玩家 id,未分出胜负用 -1 表示,int isOut 表示是否有玩家掉线,当有玩家掉线时,则认为游戏结束,掉线玩家判负;

四、游戏处理类

1. 自定义用户在线状态管理类 OnlineUserManager

其包含两个 ConcurrentHashMap 类型的属性 gameLobby,gameRoom,将用户 id 和 WebSocketSession 会话通过键值对方式存储,gameLobby 表示用户在游戏大厅的在线状态,gameroom 表示用户在游戏房间的在线状态;并为该类添加相应的方法

enterGameLobby:进入游戏大厅,在 gameLobby 中添加用户 id 和相应的 WebSocketSession;

exitGameLobby:离开游戏大厅,从 gameLobby 中删除 id 对应的键值对;

getOnline:获取用户大厅会话,通过 id 从 gameLobby 中获取相应的 WebSocketSession; 

enterGameRoom:进入游戏房间,在 gameRoom中添加用户 id 和相应的 WebSocketSession;

exitGameRoom:离开游戏房间,从 gameRoom 中删除 id 对应的键值对;

getOnlineRoom:获取用户房间会话,通过 id 从 gameRoom 中获取相应的 WebSocketSession;

即 将 ConcurrentHashMap 的 put,get,remove 等方法进行封装,分别表示用户上线,获取用户在线状态,用户下线;

2. 自定义匹配类 Matcher

其属性包含三个队列,分别表示用户的实力等级(分为正常水平,高水平和超高水平),根据用户的实力等级来匹配实力相近的玩家;其方法包括用户

进入匹配队列 add方法;用户离开匹配队列 remove 方法;构造方法,使用三个线程分别判断三个匹配队列是否匹配成功,使用 wait notify 解决忙等问题;handlerMatch 方法判断是否匹配成功,当某个队列中有两名玩家时,即匹配成功,将这两个玩家放入同一个房间中,并为两名玩家分别做出响应;

3. 自定义的房间类 Room

表示一次游戏中两名玩家对战的游戏房间,其属性分别包括 roomId 房间号,User user1 表示玩家 1,User user2 表示玩家 2,int blackUser 表示执黑子的玩家(先手权),int[][] board 表示棋盘,由于该类不应该是唯一的,有可能有多场对局同时进行,就需要多个游戏房间,故需通过构造器使用 getBean 方法注入对象,roomId 用 UUID 随机生成;其方法有 

putChess 用来处理一次落子请求:首先将客户端传递的落子请求转换为 GameRequest 对象,根据其属性 userId 判断是哪个玩家的轮次,并将棋盘 board 中对应的 row col 位置填上对应轮次玩家的标志,例如 1 表示黑子,2 表示白子,(同时判断是否有玩家离线,如果有玩家离线,则将胜方指定为未离线的玩家),同时判断游戏是否分出胜负,并将以上信息构造为 GameResponse 对象返回给每个玩家;

printBoard 在服务器端打印棋盘落子情况,以便观察是否出现异常情况;

checkWinner 判断是否决出胜负,遍历棋盘 board,判断是否存在五子连珠情况;

4. 自定义房间管理器类 RoomManager

用来管理游戏房间,其属性包括 ConcurrentHashMap<String, Room> rooms,ConcurrentHashMap<Integer, String> userToRoom,其中 rooms 将房间 id 和房间关联起来,userToRoom 的作用是将玩家 id 和房间 id 关联起来;其方法包括

add,将对应的房间 id 和房间放入 rooms 中,将 玩家 1 和房间 id 放入 玩具 2 和房间 id 分别放入userToRoom中;

remove 方法将放假 id 从 rooms 中删除,将 玩家 1 id 和玩家 2 id 分别从 userToRoom 中删除;

getRoomByUserId,通过 userId 获取到房间 id,再通过房间 id 获取到房间信息;

五、匹配模块

通过 MatchController 类实现,处理匹配时的 WebSocket 请求;该类继承自 Spring 中的TextWebSocketHandler 类,并重写其中的一些方法

1)afterConnectionEstablished 方法,该方法用来处理前后端通信时的 WebSocket 连接建立成功之后服务器应该做的逻辑,并将响应结果返回给客户端;

在连接建立之后,通过 WebSocketSession 类中提供的 getAttributes().get 方法获取到用户信息,通过用户 id 得到的 WebSocket 会话,若不为 null,则说明用户已经在其他地方登录,此时不应重复登录(由于此时还没有进行任何操作,得到的 id 对应的 WebSocket 应为 null),当 id 对应的 WebSocket 会话为null 时,将此时的 WebSocket 会话和 id 对应放入 map 中,表示用户进入游戏大厅,即用户上线; 

2)handleTextMessage 方法,该方法用来处理客户端与服务器通信过程中客户端发送的请求,并将请求处理之后的响应返回给客户端;

首先通过 WebSocketSession 类中提供的 getAttributes().get 方法获取到用户信息,通过TextMessage 提供的方法 getPayload 将请求解析为字符串,再通过 ObjectMapper类 提供的 readValue 方法将字符串 转化为 MatchRequest 对象,服务器根据客户端请求中的内容(开始匹配或者结束匹配),决定用户进入匹配队列还是离开匹配队列,并构造相应的响应并返回给客户端;

3)handleTransportError 方法,该方法用来处理当通信连接出现异常时,服务器应做的逻辑;

此时通信连接异常,说明玩家已经下线,需要将 用户 id 从 map 中删除;考虑到这样一种情况:同一个账号使用两个不同的浏览器先后登录同一个账号,此时经过 afterConnectionEstablished 方法判定之后不能重复登录,此时需将后登陆的连接关闭(但先登录的连接不应该关闭),为了防止将先登录的 webSecoket会话错误删除,此处需要再做一个判定,当当前的 WebSocketSession == 用户 id 对应的 WebSocketSession 时再进行删除,同时将用户从匹配队列中移除;

4)afterConnectionClosed 方法,该方法用户处理通信连接关闭之后,服务器应做的逻辑;同上连接异常时的处理情况;

六、游戏模块

通过 GameController 类实现,处理游戏中的 WebSocket 请求;该类继承自 Spring 中的TextWebSocketHandler 类,并重写其中的一些方法

1)afterConnectionEstablished 方法

首先,通过 WebSocketSession 类中提供的 getAttributes().get 方法获取到用户信息,如果用户为null 则直接返回一个 reason 为用户未登录的 GameReadyResponse 响应;否则,根据 RoomManager 类中的 getRoomByUserId 方法获取到玩家所在房间;如果房间不存在,则说明尚未匹配到,并返回响应;再接着判断用户是否在其他地方已经登录,通过 OnlineUserManager 获得当前用户的游戏房间状态和游戏大厅状态(WebSocketSession),如果有一个不为 null 则说明用户已经登录,返回用户多开响应;否则,就通过 OnlineUserManager 中的 enterGameRoom 方法设置该用户的游戏房间状态;判断 room 中的 user1 是否为空,若为空,则将当前玩家设置为user1,并将先手方设置为当前玩家,此时设置过一个玩家之后应该直接返回,等待第二个玩家的请求到来时,此时 room 中的 user1 已经不为空了,已经被上一个玩家先占了,此时将该玩家设置为 user2,此时 room 中的两个玩家均已连接上,需分别通知两个玩家游戏准备就绪,通过 noticeGameReady 方法实现;注意判断 user1 是否为空时,有可能两个玩家的请求同时到达,同时判定 user1 为空,此时 room 中的 user1 被设置了两次,而 user2 没有被设置,为了防止这种情况的发生,需要在判断时使用 synchronized 对 room 加锁;

2)noticeGameReady 方法的实现

该方法参数列表包含 Room room,User thisUser,User thatUser,分别表示游戏房间,玩家自己和另一个玩家,这个方法需要向客户端发送一个游戏准备就绪 GameReadyResponse 的响应,就需要通过 WebSocketSession 中的 sendMessage 方法发送,故需先通过 OnlineUserManager 中的 getOnlineRoom 方法获取到 session会话,然后构造一个 GameReadyResponse 响应并设置其中的 roomId,thisUserId,thatUserId等属性,再通过 sendMessage 发送;

3)handleTextMessage

先通过 WebSocketSession 类中提供的 getAttributes().get 方法获取到用户信息,并判断用户信息是否为空,再通过 RoomManager 中的 getRoomByUserId 获取到当前房间 room 的信息,通过调用 room 中的 putChess 方法处理一次落子请求;

4)handleTransportError

当游戏的某一方连接异常时,此处逻辑是通知另一方直接获胜,通过 noticeUserWin 方法;并改变玩家的游戏房间在线状态;

5)noticeUserWin 方法的实现

该方法参数为一个 User 对象(指掉线玩家),主要完成的功能是通知未掉线的玩家获胜,并返回响应给该玩家,并修改两名玩家的天梯分数,获胜场次,总场次等信息;

先通过 RoomManager 中的 getRoomByUserId 获取到相应的房间信息,根据房间信息,判断该通知哪个玩家获胜,构造一个 GameResponse 对象,并设置其Winner,isOut等相关信息,再将响应发送给该玩家,同时修改两名玩家数据库中的相应信息;

6)afterConnectionClosed 同上连接异常时的处理情况;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1708213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

交叉熵损失函数计算过程(tensorflow)

交叉熵损失函数通常用于多类分类损失函数计算。计算公式如下&#xff1a; P为真实值&#xff0c;Q为预测值。 使用tensorflow计算 import tensorflow as tf import keras# 创建一个示例数据集 # 假设有3个样本&#xff0c;每个样本有4个特征&#xff0c;共2个类别 # 目标标签…

简爱的思维导图怎么做?从这三个角度

简爱的思维导图怎么做&#xff1f;《简爱》作为夏洛蒂勃朗特的代表作&#xff0c;不仅是一部经典的爱情小说&#xff0c;也是探索女性独立与自我成长的文学巨著。为了深入理解这部作品&#xff0c;制作思维导图是一种高效的学习和分析工具。以下是三种不同的角度来创建《简爱》…

excel数据丢失怎么办?表格文件恢复的3个方法

Excel作为一个常用的表格文件&#xff0c;我们在工作中经常都需要用到它。最令人崩溃的事就是有时候我们辛辛苦苦用Excel完成了工作&#xff0c;但是突然发现Excel数据丢失。这可怎么办呢&#xff1f;如何找回丢失的Excel数据&#xff1f;下面小编就分享几种恢复办法。 方法一&…

抖音 v27.8.0 内置增强模块,自动播放、无水印下载(可登录,助手增强版)

介绍 抖音应用作为全球领先的短视频平台&#xff0c;其内置功能允许用户将喜欢的内容保存至本地设备&#xff0c;但默认情况下&#xff0c;这些视频会带有抖音的水印。为了解决这一限制&#xff0c;该版本使用户能够直接保存不带水印的视频到手机中&#xff0c;无需使用任何第…

TikTok电商带货特训营,跟随时代潮流,跨境掘金(8节课)

课程内容&#xff1a; 1-先导课 2-一、店铺运营认知与思路 3-二、店铺风控注意事项 4-三、美区Tiktok前期工作-1店铺入驻模式 5-三、美区Tiktok前期工作-2指纹浏览器介绍 6-三、美区Tiktok前期工作-4绑定电话号码 7-三、美区Tiktok前期工作-5添加仓库地址 8-三、美区Ti…

央视网视频下载和花屏问题处理

央视网(www.cctv.com)视频下载往往是花屏的&#xff0c;如何处理呢&#xff1f; 如果您是IT技术开发者&#xff0c;那么您可以通过下面步骤自己实现。 用chrome浏览器&#xff0c;F2打开开发者工具&#xff0c;找到当前页面的network 然后找一个接口&#xff1a;https://vdn.a…

JRebel 激活及使用

插件下载 JRebel and XRebel - IntelliJ IDEs Plugin | Marketplace 从磁盘安装下载的插件 windows下载激活服务 Releases ilanyu/ReverseProxy GitHub mac没有对应版本&#xff0c;需要Docker搭建本地激活服务 docker pull qierkang/golang-reverseproxy docker run -d -…

(2024,RWKV-5/6,RNN,矩阵值注意力状态,数据依赖线性插值,LoRA,多语言分词器)Eagle 和 Finch

Eagle and Finch: RWKV withMatrix-Valued States and Dynamic Recurrence 公众号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. Eagle/Finch 架构 4. 方法 4.1 Eagle 4.1.1 Eagle…

基于Pytorch框架的深度学习RegNet神经网络二十五种宝石识别分类系统源码

第一步&#xff1a;准备数据 25种宝石数据&#xff0c;总共800张&#xff1a; { "0": "Alexandrite","1": "Almandine","2": "Benitoite","3": "Beryl Golden","4": "Carne…

ctfshow web入门 黑盒测试

web380 这里文章看的我好有感触 但是影响做题 扫描一下 访问flag.php啥也没有再访问page.php page.php?idflagweb381 扫出来page.php但是没啥用哇&#xff0c;查看源代码 这些文件挨个试发现啥也没&#xff0c;最后仔细对比发现其实都是layui&#xff0c;然后尝试着访问…

神经网络的工程基础(零)——PyTorch基础

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 本文涉及到的代码链接如下&#xff1a;regression2chatgpt/ch06_optimizer/gradient_descent.ipynb 本文将介绍PyTorch的基础。…

Centos安装,window、ubuntus双系统基础上安装Centos安装

文章目录 前言一、准备工作二、开始安装1、2、首先选择DATE&TIME2、选择最小安装3、 选择安装位置 总结 前言 因工作需要&#xff0c;我需要在工控机上额外装Centos7系统&#xff0c;不过我是装在机械硬盘上了不知道对性能是否有影响&#xff0c;若有影响&#xff0c;后面…

MyBatis系统学习篇 - MyBatis逆向工程

MyBatis的逆向工程是指根据数据库表结构自动生成对应的Java实体类、Mapper接口和XML映射文件的过程。逆向工程可以帮助开发人员快速生成与数据库表对应的代码&#xff0c;减少手动编写重复代码的工作量。 我们在MyBatis中通过逆向工具来帮我简化繁琐的搭建框架&#xff0c;减少…

macOS上用Qt creator编译并跑shotcut

1 简介 Shotcut是一个开源的跨平台的视频编辑软件&#xff0c;支持WIN/MACOS/LINUX等平台&#xff0c;由于该项目的编译较为麻烦&#xff0c;踩坑几许&#xff0c;因此写此文章记录完整编译构建过程&#xff0c;后续按此法编译&#xff0c;可减少走弯路&#xff0c;提高生产力。…

vue+antd实践:在输入框光标处插入内容

今天来看一个很简单的需求。 需求描述&#xff1a;在输入框光标处&#xff0c;插入指定的内容。 效果如下&#xff1a; 实现思路&#xff1a;刚开始还在想怎么获取光标的位置&#xff0c;但是发现所做的项目是基于vue3antd组件&#xff0c;那么不简单了嘛&#xff0c;只要调…

SpringBoot Redis 扩展高级功能

环境&#xff1a;SpringBoot2.7.16 Redis6.2.1 1. Redis消息发布订阅 Spring Data 为 Redis 提供了专用的消息传递集成&#xff0c;其功能和命名与 Spring Framework 中的 JMS 集成类似。Redis 消息传递大致可分为两个功能区域&#xff1a; 信息发布 信息订阅 这是一个通常…

[XYCTF新生赛]-Reverse:你是真的大学生吗?解析(汇编异或逆向)

无壳 查看ida 没有办法反汇编&#xff0c;只能直接看汇编了。 这里提示有输入&#xff0c;输入到2F地址后&#xff0c;然后从后往前异或&#xff0c;其中先最后一个字符与第一个字符异或。这里其实也有字符串的长度&#xff0c;推测应该是cx自身异或之后传给了cx 完整exp&am…

三分钟轻松搞定内容,2024视频号最新AI自动生成影视解说,,百分之百过原创, 月入1万+

在这个数字时代&#xff0c;我们有幸见证了AI技术对创新的推动。现如今&#xff0c;一个崭新的平台出现了&#xff0c;它能让你用AI软件在短短3分钟内制作完成一段影视解说&#xff0c;而且由于这个平台尚属于新兴&#xff0c;竞争者稀少&#xff0c;提供了一个广阔的机遇天地。…

如何将云服务器上操作系统由centos切换为ubuntu

本文将介绍如何将我们购买的云服务器上之前装的centos切换为ubuntu&#xff0c;云服务器以华为云为例&#xff0c;要切换的ubuntu版本为ubuntu20.04。 参考官方文档&#xff1a;切换操作系统_弹性云服务器 ECS (huaweicloud.com) 首先打开华为云官网&#xff0c;登录后点击右…

多模态MLLM都是怎么实现的(9)-时序LLM是怎么个事儿?

时序预测这东西大家一般不陌生,随便举几个例子 1- 金融,比如预测股票(股市有风险,入市需谨慎),纯用K线做,我个人不太推荐 2- 天气,比如预测云图,天气预报啥的 3- 交通,早晚高峰,堵车啥的,车啥时候加油,啥时候充电之类的 4- 医疗,看你病史和喝酒的剂量建模,看你会…