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

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

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 同上连接异常时的处理情况;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

班翠鸟优化算法(PKO)-2024年SCI新算法-公式原理详解与性能测评 Matlab代码免费获取

​ 声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理简介 一、初始化阶段 二、栖…

C# 字节数组(byte[])拼接的性能对比测试

将C#中的三种字节数组拼接方式的性能做了一个对比测试&#xff0c;DEMO程序代码如下&#xff1a; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks;namespace Byte数组拼接测…

typora自动生成标题序号(修改V1.0)

目录 带序号效果图 解决方法 带序号效果图 解决方法 1.进入文件夹&#xff1a;文件–>偏好设置–>外观–>主题–>打开主题文件夹 2.如果没有base.user.css文件&#xff0c;新建一个。如果有直接用记事本打开&#xff0c;把下面代码拷贝进去保存。 /** initiali…

免税商品优选购物商城,基于 SpringBoot+Vue+MySQL 开发的前后端分离的免税商品优选购物商城设计实现

目录 一. 前言 二. 功能模块 2.1. 登录界面 2.2. 管理员功能模块 2.3. 商家功能模块 2.4. 用户前台功能模块 2.5. 用户后台功能模块 三. 部分代码实现 四. 源码下载 一. 前言 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过…

前端开发之xlsx-js-style的使用和实例

xlsx-js-style的使用和实例 前言效果图安装xlsx-js-style插件导入插件在创建ws后设置表头 前言 在使用xlsx组件的时候如果需要调整xlsx表的样式可以使用xlsx-js-style来进行设置 效果图 安装xlsx-js-style插件 npm install xlsx-js-style导入插件 该文件参考在xlsx的使用中…

各种情况下的线缆大小选择

开口线鼻子和导线对应大小 开口铜鼻子对应线径大小 变压器容量对应高压侧电流大小 开关电流线缆功率对照表 家庭/工业最常用电线铜线电流承载功率 电工常用名词对应符号 导线面积承载的安全载流量及允许负荷对照表 漏电保护器选择参考表 电动机功率换算电流 电机功…

数据(整型和浮点数)在内存中的存储

目录 1.整型在内存中的存储 大小端字节序存储和字节序判断 1.大小端字节序存储&#xff1a; 2.字节序判断&#xff1a; 2.浮点数在内存中的存储 浮点数存储的过程 浮点数读取的过程 题目解析 1.整型在内存中的存储 我们先要明白&#xff1a; 整数在内存中是以二进制形式…

数据结构(六)队列

文章目录 一、概念二、逻辑结构&#xff1a;线性结构三、存储结构&#xff08;一&#xff09;顺序队列&#xff08;二&#xff09;循环队列1. 结构体定义2. 创建队列&#xff08;1&#xff09;函数定义&#xff08;2&#xff09;注意点&#xff08;3&#xff09;代码实现 3. 入…

SQLI-labs-第二十五关和第二十五a关

目录 第二十五关 1、判断注入点 2、判断数据库 3、判断表名 4、判断字段名 5、获取数据库的数据 第二十五a关 1、判断注入点 2、判断数据库 第二十五关 知识点&#xff1a;绕过and、or过滤 思路&#xff1a; 通过分析源码和页面&#xff0c;我们可以知道对and和or 进…

解决 WooCommerce 的分析报表失效问题

今天明月的一个境外电商客户反应网站的 WooCommerce 分析报表已经十多天没有更新了&#xff0c;明明每天都有订单交易可分析报表里的数据依旧是十多天前的&#xff0c;好像更新完全停滞了似的。明月也及时的查看了后台的所有设置&#xff0c;确认没有任何问题&#xff0c;WooCo…

什么是光栅化?

一、 什么是光栅化? 光栅化作用是将几何数据变换后转换为像素呈现在显示设备上的一个过程。几何数据转换为像素&#xff0c; 本质是坐标变换、几何离散化&#xff0c;如下&#xff1a; 其中包含了坐标变换和几何离散化&#xff1a; 二、光栅化完成了什么 3D中&#xff0c;物…

数组-两个升序数组中位数

一、题目描述 二、解题思路 (一).基本思想&#xff1a; 如果列表总长度allsize( arr1.size()arr2.size() ) 为奇数时&#xff0c;中位数位置应该在两个列表排序后的第 allsize/2 位置处&#xff0c;如果allsize为偶数&#xff0c;中位数应该取 (allsize/2)-1 和 allsize/2 的…

Google Extension 【Google 最佳扩展插件】

pockettube: youtube manager 订阅号分组沉浸式翻译&#xff1a;全网口碑炸裂的双语对照网页翻译插件Google 翻译腾讯翻译篡改猴MetaMaskGlarity: Summarize & Translate Any Page

移动端应用订阅SDK接入攻略

本文档介绍了联想应用联运移动端订阅SDK接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运移动端订阅SDK。 接入前准备 1请先与联想商务达成合作意向。 2.联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#…

卸载/删除 Maxask.com,最简单的方法

被绑架的浏览器&#xff0c;太恶心了。 Maxask伪装成了插件&#xff0c;在你搜索网页的时候利用了重定向&#xff0c;导致出现的界面时Maxask的界面&#xff0c;很恶心。 只需要排查正在使用的&#xff0c;如下图有颜色的图表。 删除一个插件&#xff0c;浏览器搜索一下看看有…

2024年上半年软件设计师试题及答案(回忆版)--选择题

基础知识选择题 基础知识选择题 1,2,3][4,5,6][1,2,3,4,5,6] &#xff08;总&#xff1a;1分&#xff09; &#xff08;注意&#xff1a;括号内的是截止当前题目总分&#xff09; vlan不能隔绝内外网 &#xff08;2分&#xff09; 链路层使用交换机&#xff0c;…

C语言 | Leetcode C语言题解之第115题不同的子序列

题目&#xff1a; 题解&#xff1a; int numDistinct(char* s, char* t) {int m strlen(s), n strlen(t);if (m < n) {return 0;}unsigned long long dp[m 1][n 1];memset(dp, 0, sizeof(dp));for (int i 0; i < m; i) {dp[i][n] 1;}for (int i m - 1; i > 0;…

M2m中的采样

采样的完整代码 import torch import numpy as np from torchvision import datasets, transforms from torch.utils.data import DataLoader, WeightedRandomSampler, SubsetRandomSamplerdef get_oversampled_data(dataset, num_sample_per_class):""" Gener…

Brewer Science将在CS Mantech进行展示

在风景如画的亚利桑那州图森市举办的CS Mantech盛会上&#xff08;2024年5月20日至23日&#xff09;&#xff0c;杰出化合物半导体材料企业Brewer Science&#xff0c;将带来一场名为“化合物半导体制造的创新材料解决方案”的演讲盛宴。这一演讲&#xff0c;定于五月二十一日星…

宝塔:如何在宝塔面板做301重定向

如何在宝塔面板做301重定向?301重定向对于网站来说非常重要。如果你的网站以www开头&#xff0c;我们应该把没有www的域名重定向到有www的域名&#xff0c;反之亦然。 1、我们进入宝塔管理后台 2、登录面板并单击添加站点。既然要把xxx.com 301发到www.xxx.com&#xff0c;我…