项目一:使用 Spring + SpringMVC + Mybatis + lombok 实现网络五子棋

一:系统展示:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

二:约定前后端接口

2.1 登陆

登陆请求:

GET /login HTTP/1.1
Content-Type: application/x-www-form-urlencodedusername=zhangsan&password=123

登陆响应:

  1. 正常对象:正常对象会在数据库中存储,直接从数据库中取出即可,无需通过 set 方法进行设置
HTTP/1.1 200 OK
Content-Type: application/json{"userid": 1,"username": "zhangsan","password": "123","score": 1000,"totalcount": 0,"wincount": 0
}
  1. 登陆失败返回空对象
HTTP/1.1 200 OK
Content-Type: application/json{"userid": 0,"username": null,"score": 0,"totalcount": 0,"wincount": 0
}

2.2 注册

  1. 注册请求
GET /register HTTP/1.1
Content-Type: application/x-www-form-urlencodedusername=zhangsan&password=123
  1. 注册响应
HTTP/1.1 200 OK
Content-Type: application/json{"userid": 1,"username": "zhangsan","password": "123","score": 1000,"totalcount": 0,"wincount": 0
}
  1. 获取当前用户信息
GET /userinfo HTTP/1.1
Content-Type: application/json{"userid": 1,"username": "zhangsan","score": 1000,"totalcount": 0,"wincount": 0
}

2.2 匹配

  1. 匹配请求
ws://127.0.1:8080/Match{"message": "startMatch" / ”stopMatch“    //startMatch 代表开始匹配,stopMatch 代表停止匹配
}

请求不必带有用户的信息。因为在登陆成功后会把用户信息保存在 httpsession 中,websocket 可以拿到这个 httpseesion中存储的数据。

  1. 匹配响应 1
ws://127.0.0.1:8080/Match{"ok": true,                            // 进入成功为 true  匹配成功,否则为 false"reason": "失败原因",                   // 失败原因(若匹配失败则返回此字段)"message": "startMatch" / "stopMatch"/'matchSuccess'/'repeatConnection'  //startMatch 代表开始匹配,stopMatch 代表停止匹配 ,matchSuccess 代表匹配成功 ,'repeatConnection 代表用户多开
}

2.3 对战

对战和匹配使用两套逻辑,使用不同的 websocket 路径处理,能够更好的解耦合

  1. 响应 1 gameready
{"message": "gameReady","ok": true,                       // 匹配成功为 true,否则为 false,false 代表有某些问题"reason": "",                     // 出错原因(若匹配失败则返回此字段)"roomid": "123456",               // 房间 ID"thisuserid": 1,                  // 自己的用户 ID"thatuserid": 2,                  // 对手的用户 ID"whiteuser": 1                    // 先手玩家 ID,1 表示自己先,2 表示对手先
}

这个请求是玩家匹配成功后,由服务器生成的内容,把这个内容返回给浏览器

  1. 下棋请求 1
{"message": "putChess","userid": 1,"row": 0,"col": 0
}
  1. 下棋响应
{"message": "putChess","userid": 1,"row": 0,              // 行"col": 0,              // 列"winner": 0            // 当前是否分出胜负,0 代表无胜负,非 0 代表获胜方用户 ID
}

三: websocket 前置知识

对于 http 来说,能够实现客户端向服务器发送数据,但是很难实现服务器向客户端发送数据,虽然可以通过轮转实现,但是这种实现太消耗cpu,性能也不好,而且实现起来也比较麻烦,所以我们选择使用 websocket 协议,websocket 协议能实现客户端和服务器的双向通信,符合我们目前的需求场景。

WebSocket 与 HTTP 的区别

  • 持久连接:WebSocket 连接建立后会一直保持,直到显式关闭,减少了多次连接开销。
  • 双向通信:WebSocket 支持全双工通信,即客户端和服务器可以在任意时间发送消息。
  • 低延迟:WebSocket 的头部信息少,通信延迟低,非常适合实时性要求高的应用场景。

使用 WebSocket 的场景

  • 实时聊天系统(如在线客服、聊天应用)
  • 在线游戏(如棋类对战、竞技游戏)
  • 实时数据推送(如股票行情、天气更新、体育比分)

3.1 websocket 连接流程

使用 WebSocket 连接的步骤:

  • 后端配置 WebSocket 端点:定义 WebSocket 端点的 URL,客户端通过该 URL 连接到服务器。
  • 实现 TextWebSocketHandler 类:处理 WebSocket 连接事件,包括连接建立、接收消息、连接关闭等。
  • 前端建立 WebSocket 连接:前端使用 JavaScript 创建 WebSocket 连接,发送和接收消息。

步骤一:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new ChatHandler(), "/chat"); // 将 /chat 端点与 ChatHandler 绑定}
}
  • /chat:这是客户端连接的 WebSocket URL(端点)。
  • ChatHandler:我们自定义的 WebSocket 处理器,用来处理 WebSocket 的事件。

步骤 2:实现 TextWebSocketHandler 类

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;public class ChatHandler extends TextWebSocketHandler {//TextWebSocketHandler 是 Spring 提供的一个辅助类,用于处理 WebSocket 的文本消息。// 1. 连接建立时调用@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {System.out.println("连接已建立:" + session.getId());}// 2. 接收到消息时调用@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {System.out.println("收到消息:" + message.getPayload());// 将收到的消息返回给客户端session.sendMessage(new TextMessage("服务器响应:" + message.getPayload()));}// 3. 连接关闭时调用@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {System.out.println("连接已关闭:" + session.getId());}// 4. 处理错误时调用@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {System.err.println("传输错误:" + exception.getMessage());}
}
  • afterConnectionEstablished:当客户端成功连接时调用,比如用户打开 WebSocket
    页面。这时候我们可以进行一些初始化操作。
  • handleTextMessage:当服务器接收到客户端发送的消息时调用。这里我们简单地把接收到的消息再发送回客户端。
  • afterConnectionClosed:当 WebSocket 连接关闭时调用,比如用户关闭页面或断开连接。我们可以在这里进行一些清理操作。
  • handleTransportError:当连接出错时调用,例如网络故障。可以在这里记录错误日志或进行错误处理。

步骤三:前端实现

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket 示例</title>
</head>
<body><h2>WebSocket 简单示例</h2><div><input type="text" id="messageInput" placeholder="输入消息"><button onclick="sendMessage()">发送消息</button></div><div id="response"></div><script>// 1. 创建 WebSocket 连接let websocket = new WebSocket("ws://" + location.host + "/chat");//建立连接// 2. 连接建立时调用websocket.onopen = function() {console.log("WebSocket 连接已建立");};// 3. 接收消息时调用websocket.onmessage = function(event) {console.log("收到消息:" + event.data);document.getElementById("response").innerText = "服务器:" + event.data;};// 4. 连接关闭时调用websocket.onclose = function() {console.log("WebSocket 连接已关闭");};// 5. 出错时调用websocket.onerror = function(error) {console.error("WebSocket 出现错误:" + error);};// 发送消息给服务器function sendMessage() {let message = document.getElementById("messageInput").value;websocket.send(message); // 发送消息}</script>
</body>
</html>
  • new WebSocket(“ws://” + location.host + “/chat”):创建 WebSocket 连接到服务器 /chat 端点绑定的 WebSocket 处理器上。
  • onopen:当连接成功时调用,可以在这里通知用户连接已建立。
  • onmessage:当接收到服务器发送的消息时调用。我们将接收到的消息显示在页面上。
  • onclose:当连接关闭时调用,可以在这里通知用户连接已关闭。
  • onerror:当连接出错时调用。

通过这三个步骤就可以把特定的前端页面和特定的后端类进行连接并通信了

3.2 客户端和服务器互发数据

在 WebSocket 通信中,客户端和服务器都可以通过特定的方法发送数据。

3.2.1 客户端发送数据给服务器

在前端,客户端使用 WebSocket.send() 方法向服务器发送数据。

// 假设已经创建了 WebSocket 连接
let websocket = new WebSocket("ws://" + location.host + "/chat");// 定义一个函数,通过 WebSocket 向服务器发送消息
function sendMessage() {let message = document.getElementById("messageInput").value; // 获取输入框中的消息websocket.send(message); // 使用 send 方法发送消息给服务器console.log("发送消息给服务器:" + message);
}

3.2.2 服务器发送数据给客户端

在 Spring Boot 中,服务器使用 WebSocketSession.sendMessage() 方法向客户端发送数据。

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;public class ChatHandler extends TextWebSocketHandler {@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {System.out.println("收到客户端消息:" + message.getPayload());// 构造服务器的响应消息TextMessage responseMessage = new TextMessage("服务器响应:" + message.getPayload());// 发送响应消息给客户端session.sendMessage(responseMessage);System.out.println("发送消息给客户端:" + responseMessage.getPayload());}
}

数据通过 sendMessage 发送数据后,前端会调用 onmessage 方法


3.3 Json数据 Java对象 JS对象的互相转换

在 Web 开发中,我们经常需要在客户端(JavaScript)和服务器端(Java)之间传递数据,通常会使用 JSON 格式。以下是 JSON 字符串与 JavaScript 对象、Java 对象之间的互相转换方法。

在前端,前端需要 JS 对象,而在后端,后端需要 Java 对象,而他们传输的数据都是 Json 格式的数据,所以当我们传输数据的时候就涉及到了这三个对象的互相转换

  • 前端发送数据:JavaScript 对象 → JSON 字符串 → 发送给后端。
  • 后端接收数据:JSON 字符串 → Java 对象 → 处理。
  • 后端返回数据:Java 对象 → JSON 字符串 → 发送给前端。
  • 前端接收数据:JSON 字符串 → JavaScript 对象 → 处理。

3.3.1 JSON 字符串与 JavaScript 对象的转换

3.3.1.1 JavaScript 对象转为 JSON 字符串

使用 JSON.stringify() 方法将 JavaScript 对象转换为 JSON 字符串。

let jsObject = {name: "张三",age: 25,city: "北京"
};// 将 JavaScript 对象转换为 JSON 字符串
let jsonString = JSON.stringify(jsObject);
console.log(jsonString); 
// 输出: {"name":"张三","age":25,"city":"北京"}
3.3.3.2 JSON 字符串转为 JavaScript 对象

使用 JSON.parse() 方法将 JSON 字符串转换为 JavaScript 对象。

let jsonString = '{"name":"张三","age":25,"city":"北京"}';// 将 JSON 字符串转换为 JavaScript 对象
let jsObject = JSON.parse(jsonString);
console.log(jsObject.name); 
// 输出: 张三

3.3.2、JSON 字符串与 Java 对象的转换

3.3.2.1 引入 Jackson 依赖

如果使用 Maven 项目,在 pom.xml 中添加 Jackson 的依赖:

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.3</version>
</dependency>
3.2.2.2 JSON 字符串转为 Java 对象

使用 ObjectMapper 类的 readValue() 方法将 JSON 字符串转换为 Java 对象。

import com.fasterxml.jackson.databind.ObjectMapper;public class JsonExample {public static void main(String[] args) throws Exception {String jsonString = "{\"name\":\"张三\",\"age\":25,\"city\":\"北京\"}";// 创建 ObjectMapper 实例ObjectMapper objectMapper = new ObjectMapper();// 将 JSON 字符串转换为 Java 对象Person person = objectMapper.readValue(jsonString, Person.class);System.out.println(person.getName()); // 输出: 张三}
}class Person {private String name;private int age;private String city;// Getters and Setterspublic String getName() { return name; }public void setName(String name) { this.name = name; }public int getAge() { return age; }public void setAge(int age) { this.age = age; }public String getCity() { return city; }public void setCity(String city) { this.city = city; }
}
3.2.2.3 Java 对象转为 JSON 字符串

使用 ObjectMapper 类的 writeValueAsString() 方法将 Java 对象转换为 JSON 字符串。

import com.fasterxml.jackson.databind.ObjectMapper;public class JsonExample {public static void main(String[] args) throws Exception {// 创建一个 Java 对象Person person = new Person();person.setName("张三");person.setAge(25);person.setCity("北京");// 创建 ObjectMapper 实例ObjectMapper objectMapper = new ObjectMapper();// 将 Java 对象转换为 JSON 字符串String jsonString = objectMapper.writeValueAsString(person);System.out.println(jsonString); // 输出: {"name":"张三","age":25,"city":"北京"}}
}

四:会话的相关知识

会话创建和持续时间

  • 当用户第一次访问服务器(例如第一次登录或访问某个页面)时,服务器会为用户创建一个新的会话,并生成一个唯一的会话 ID。
  • 服务器会将这个会话 ID 发送给客户端。
  • 在这个会话期间,用户的所有请求都会携带这个会话 ID,服务器通过这个 ID 识别请求来自同一用户,继续使用相同的会话对象。

会话过期或手动销毁

  • 会话有一个过期时间(通常设置在服务器的配置中,例如 30 分钟或其他时间),如果用户在过期时间内没有任何活动(即没有请求发给服务器),会话将自动失效。
  • 用户也可以通过主动“退出登录”来销毁会话,此时服务器会手动调用 session.invalidate() 方法,立即销毁会话,并清除所有会话中的数据。

再次登录会创建新会话

  • 如果用户退出登录或会话过期,用户再进行登录时,服务器通常会创建一个新的会话。
  • 新的会话会重新生成会话 ID,不再使用之前的 ID,因此之前的会话数据不会继续保留。

五:源代码

gittee 地址

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

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

相关文章

vue 插槽

参考文档 插槽 Slots | Vue.js 1. 基本概念 Vue的插槽&#xff08;slot&#xff09;&#xff0c;简单来说&#xff0c;就是一种 定义在组件中的 “占位符”。用于实现现组件的内容分发和复用。如下&#xff0c;是一个简单的默认插槽&#xff1a; <!-- Parent.vue --> &…

信息流不同行业账户流量池有区别吗?

在投放过程中&#xff0c;我们经常遇到这么一个问题&#xff0c;不同行业账户投放&#xff0c;流量池会有区别嘛&#xff1f;我认为是有的&#xff0c;那么对于我们而言&#xff0c;怎么样才能利用好媒体对于流量池的划分效果&#xff0c;可以从以下几个方面来进行考虑&#xf…

[Tex] Ubuntu 搭建 TexWork

更新软件库 打开终端&#xff1a; sudo apt --update sudo apt --upgrade 安装 texlive 完整版与 TexWorks 界面 sudo apt install texlive-full sudo apt install texworks

从0开始深度学习(26)——汇聚层/池化层

池化层通过减少特征图的尺寸来降低计算量和参数数量&#xff0c;同时增加模型的平移不变性和鲁棒性。汇聚层的主要优点之一是减轻卷积层对位置的过度敏感。 1 最大汇聚层、平均汇聚层 汇聚层和卷积核一样&#xff0c;是在输入图片上进行滑动计算&#xff0c;但是不同于卷积层的…

地图带你看三山五岳-基于Leaflet的重点旅游专题实现

目录 前言 一、关于三山五岳 1、三山五岳简介 2、位置信息检索 二、使用Leaflet进行WebGIS标注 1、基础数据准备 2、点位标绘 三、实际效果 1、整体效果 2、东岳泰山 3、西岳华山 4、南岳衡山 5、北岳恒山 6、 中岳嵩山 四、总结 前言 在信息技术飞速发展的今…

营销邮件策略:提升打开率和转化率的技巧!

营销邮件的发送技巧有哪些&#xff1f;如何提高营销邮件召唤力&#xff1f; 随着邮件数量的激增&#xff0c;如何确保您的营销邮件能够脱颖而出&#xff0c;提升打开率和转化率&#xff0c;成为了每个营销人员必须面对的挑战。MailBing将深入探讨一系列有效的营销邮件策略&…

libaom 源码分析:帧间运动矢量预测

AV1 帧间运动矢量预测原理 运动矢量可以被相邻块预测,这些相邻块可以是空域相邻块,或位于参考帧中的时域相邻块;通过检查所有这些块,将确定一组运动矢量预测器,并用于编码运动矢量信息。空域运动矢量预测 两组空域相邻块可以被利用寻找空域 MV 预测器,第一组包括当前块的…

轮播图【HTML+CSS+JavaScript】

给大家分享一个很好看的轮播图&#xff0c;这个也是之前看到别人写的效果感觉很好看&#xff0c;所以后面也自己实现了一下&#xff0c;在这里分享给大家&#xff0c;希望大家也可以有所收获 轮播图效果&#xff1a; 视频效果有点浑浊&#xff0c;大家凑合着看&#xff0c;大家…

OneRestore: A Universal Restoration Framework for Composite Degradation 论文阅读笔记

这是武汉大学一作单位的一篇发表在ECCV2024上的论文&#xff0c;文章代码开源&#xff0c;文章首页图如下所示&#xff0c;做混合图像干扰去除&#xff0c;还能分别去除&#xff0c;看起来很牛逼。文章是少见的做混合图像干扰去除的&#xff0c;不过可惜只包含了3种degradation…

基于Springboot的任务发布平台设计与实现(源码齐全+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

centos7 kafka高可用集群安装及测试

前言 用三台虚拟机centos7 搭建高可用集群&#xff0c;及测试方法 高可用搭建的方法&#xff0c;参考&#xff1a;https://blog.csdn.net/u011197085/article/details/134070318 高可用搭建 1、安装配置zookeeper集群 下载zookeeper 注&#xff1a;zookeeper链接如果失效&a…

30条勒索病毒处置原则

当前&#xff0c;勒索病毒在全球范围内肆虐&#xff0c;成为企业数据资产安全的头号威胁。这些狡猾的恶意软件&#xff0c;如同网络空间中的幽灵&#xff0c;不断寻找并利用系统的漏洞&#xff0c;通过加密数据或窃取敏感信息&#xff0c;向企业索取高额赎金。一旦感染&#xf…

推荐一款业内领先的建模工具:SAP PowerDesigner

SAP PowerDesigner是一款业内领先的建模工具&#xff0c;帮助您改进商务智能&#xff0c;打造更卓越的信息架构。通过该软件的元数据管理功能&#xff0c;可以构建关键信息资产的 360 度全方位视图&#xff0c;从而使数据管理、BI、数据集成和数据整合工作大获裨益。其分析功能…

6本SCI/SSCI被解除「On Hold」, 重新回归, 单位如何认定?还能投吗?

【SciencePub学术】截止至2024年10月&#xff0c;被WOS数据标记的on hold 期刊&#xff0c;共计25本&#xff0c;其中已有6本解除on hold, 重回SCI,SSCI。今天小编就带大家盘点这些“出狱”期刊情况&#xff0c;分析一下这些期刊是否还能投&#xff0c;值得投&#xff1f; 01In…

Linux下GCC编译器的安装

Linux下GCC编译器的安装 以下所有的版本都可以在https://gcc.gnu.org/pub/gcc/infrastructure/这里找最新的 通过apt-get方式下载的Qt5.9的gcc编译器版本只是4.8.3&#xff0c;无法打开一些Qt5的库头文件&#xff0c;所以准备在Llinux下再安装一个gcc5.3.0。 查看gcc版本 ubu…

【Linux】

软件包管理器 yum yum类似应用商店客户端&#xff0c;有人已经把软件写好放在服务器上了&#xff0c;通过yum找到服务器上的软件下载 软件操作 yum list 可以显示所有可下载软件&#xff0c;我们要找lrzsz软件 yum install 下载 yum remove 卸载 yum源 yum下载软件是通过…

【论文复现】基于图卷积网络的轻量化推荐模型

本文所涉及所有资源均在这里可获取。 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐、摄影的一位博主。 &#x1f4d7;本文收录于论文复现系列&#xff0c;大家有兴趣的可以看一看…

天命人开店日记之门店经营调研(下)

在调研前拟定了一些想要去了解的信息&#xff0c;包括&#xff1a;月销量、净利润、用户购买的主要担忧、与电商平台的竞争差异等关键内容&#xff0c;然而当自己去实地考察线下门店时&#xff0c;确发现实际情况与自己的预期相差非常大。大大出乎预料的包括三方面&#xff1a;…

桑基图在医学数据分析中的更复杂应用示例

桑基图&#xff08;Sankey Diagram&#xff09;能够有效地展示复杂的流动关系&#xff0c;特别适合用于医学数据分析中的多种转归和治疗路径的可视化。接下来&#xff0c;我们将构建一个稍微复杂的示例&#xff0c;展示不同疾病患者在治疗过程中的流动&#xff0c;以及他们的治…

【linux】再谈网络基础(一)

1. 再谈 "协议" 协议是一种 "约定"&#xff0c;在读写数据时, 都是按 "字符串" 的方式来发送接收的. 但是这里我们会遇到一些问题&#xff1a; 如何确保从网上读取的数据是否是完整的&#xff0c;区分缓冲区中的由不同客户端发来的数据 2. 网…