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

news2024/11/6 0:36:18

一:系统展示:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

二:约定前后端接口

2.1 登陆

登陆请求:

GET /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=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-urlencoded

username=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 {

    @Override
    public 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. 连接建立时调用
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("连接已建立:" + session.getId());
    }

    // 2. 接收到消息时调用
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("收到消息:" + message.getPayload());
        // 将收到的消息返回给客户端
        session.sendMessage(new TextMessage("服务器响应:" + message.getPayload()));
    }

    // 3. 连接关闭时调用
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("连接已关闭:" + session.getId());
    }

    // 4. 处理错误时调用
    @Override
    public 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 {

    @Override
    protected 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 Setters
    public 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.coloradmin.cn/o/2230969.html

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

相关文章

CentOS7配置静态IP(非解决方法指导,纯笨蛋记录)

一、这篇博客算是记录我终于解决我安装的虚拟机ping不通外网的问题&#xff0c;前前后后我尝试了很多次花了很多时间&#xff0c;最后弄完发现其实都是因为我之前根本不知道什么是虚拟机的网络配置。。。。。 这个链接介绍了vmware虚拟机三种网络模式及配置详解_vmware 特定虚…

opencv-day2-图像预处理1

图像预处理 在计算机视觉和图像处理领域&#xff0c;图像预处理能够提高后续处理&#xff08;如特征提取、目标检测等&#xff09;的准确性和效率。 常见的图像预处理操作&#xff1a; 图像色彩空间转换 图像大小调整 图像仿射变换 图像翻转 图像裁剪 图像二值化处理 图…

3DDFA-V3——基于人脸分割几何信息指导下的三维人脸重建

1. 研究背景 从二维图像中重建三维人脸是计算机视觉研究的一项关键任务。在虚拟现实、医疗美容、计算机生成图像等领域中&#xff0c;研究人员通常依赖三维可变形模型&#xff08;3DMM&#xff09;进行人脸重建&#xff0c;以定位面部特征和捕捉表情。然而&#xff0c;现有的方…

Ubuntu系统如何实现键盘按键映射到其他按键(以 Ctrl+c 映射到 F3,Ctrl+v 映射到 F4 为例)

文章目录 写在前面1. 功能描述2. 实现步骤2.1 安装AutoKey2.2 软件设置2.2.1 软件设置 2.3 测试是否安装成功 参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04 1. 功能描述 Ubuntu系统使用Ctrlc 、Ctrlv 进行复制粘贴操作的时候&#xff0c;时间长了就会出现小拇指…

【Clickhouse】客户端连接工具配置

ClickHouse 是什么 ClickHouse 是一个分布式实时分析型列式存储数据库。具备高性能&#xff0c;支撑PB级数据&#xff0c;提供实时分析&#xff0c;稳定可扩展等特性。适用于数据仓库、BI报表、监控系统、互联网用户行为分析、广告投放业务以及工业、物联网等分析和时序应用场…

postman的脚本设置接口关联

pm常用的对象 变量基础知识 postman获取响应结果的脚本的编写 下面是购物场景存在接口信息的关联 登录进入---搜索商品---进入商品详情---加入购物车 资源在附件中&#xff0c;可以私聊单独发送 postman的SHA256加密 var CryptoJS require(crypto-js);// 需要加密的字符串 …

Qt 文件目录操作

Qt 文件目录操作 QDir 类提供访问系统目录结构 QDir 类提供对目录结构及其内容的访问。QDir 用于操作路径名、访问有关路径和文件的信息以及操作底层文件系统。它还可以用于访问 Qt 的资源系统。 Qt 使用“/”作为通用目录分隔符&#xff0c;与“/”在 URL 中用作路径分隔符…

qt QCheckBox详解

QCheckBox 是 Qt 框架中的一个控件&#xff0c;用于创建复选框&#xff0c;允许用户进行选择和取消选择。它通常用于表单、设置界面和任何需要用户选择的场景。 QCheckBox继承自QAbstractButton类&#xff0c;因此继承了按钮的特性。它表示一个复选框&#xff0c;用户可以通过…

读数据工程之道:设计和构建健壮的数据系统26数据建模

1. 数据建模 1.1. 良好的数据架构必须反映出使用这些数据的组织的业务目标和业务逻辑 1.2. 数据湖1.0、NoSQL和大数据系统的兴起&#xff0c;使工程师们有时是为了合理的性能提升去忽略传统的数据建模 1.3. 数据在企业中的地位急剧上升&#xff0c;人们越来越认识到&#xf…

2025生物发酵展(济南)为生物制造产业注入新活力共谱行业新篇章

2025第十四届国际生物发酵展将于3月3-5日济南盛大举办&#xff01;产业链逐步完整&#xff0c;展会面积再创历史新高&#xff0c;展览面积较上届增涨至60000平方米&#xff0c;专业观众40000&#xff0c;品牌展商800&#xff0c;同期活动会议增加至50场&#xff0c;展会同期将举…

Windows版 nginx安装,启动,目录解析,常用命令

Windows版 nginx安装&#xff0c;启动&#xff0c;目录解析&#xff0c;常用命令 一级目录二级目录三级目录 1. 下载2. 启动方式一&#xff1a;方式二&#xff1a; 3. 验证是否启动4. 安装目录解析5. 常用命令 一级目录 二级目录 三级目录 1. 下载 官网下载&#xff1a;ngi…

【maven】idea执行了maven的install命令给本地安装项目依赖包 安装后删除

目录 事件起因环境和工具操作过程解决办法1、找到对应的目录下的文件&#xff0c;手动去删除&#xff0c;比如我的依赖库的路径是D:\qc_code\apache-maven-3.8.2\repository 我只需要找到这个目录下对应的依赖包进行手动删除即可&#xff08;不推荐&#xff0c;强行删除文件夹文…

技术选型不当对项目的影响与补救措施

在项目管理中&#xff0c;初期技术选型与项目需求不匹配的情况并不罕见&#xff0c;这可能导致项目延误、成本增加和最终成果的不理想。补救的关键措施包括&#xff1a;重新评估技术选型、加强团队沟通、实施有效的需求管理以及建立持续的反馈机制。其中&#xff0c;重新评估技…

基于SSM+VUE宠物医院后台管理系统JAVA|VUE|Springboot计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统&#xff1a;Window操作系统 2、开发工具&#xff1a;IntelliJ IDEA或者Eclipse 3、数据库存储&#xff1a…

MySQL 8.0在windows环境安装及配置

文章目录 一、下载二、安装三、配置环境变量 一、下载 1、先彻底卸载之前的MySQL&#xff0c;并清理其 残留文件 。 2、登录网址https://www.mysql.com/ 3、点击网址左下角“中文”按钮&#xff0c;切换到中文界面 4、点击网页上方的“下载”按钮&#xff0c;然后点击网页…

【传知代码】用于图像识别的判别图正则化技术

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;传知代码 欢迎大家点赞收藏评论&#x1f60a; 目录 论文概述图正则化技术及其优点参考文献&#xff1a; 算法流程在标准BLS中嵌入判别图正则化的方法 模型整体架构代码复现图拉普拉斯矩阵的构建—…

第二十五章 Vue父子通信之sync修饰符

目录 一、概述 二、完整代码 2.1. main.js 2.2. App.vue 2.3. BaseDialog.vue 三、运行效果 一、概述 前面的章节我们讲到&#xff0c;通过v-model我们可以实现父子组件间的通信&#xff0c;但是使用v-model的时候&#xff0c;子组件接收的prop属性名必须固定为valu…

头歌——机器学习(逻辑回归)

文章目录 逻辑回归简述代码 sklearn逻辑回归 - 手写数字识别代码 逻辑回归算法详解似然与概率的区别逻辑回归算法的代码实现代码 逻辑回归案例 - 癌细胞精准识别代码 逻辑回归简述 什么是逻辑回归 当一看到“回归”这两个字&#xff0c;可能会认为逻辑回归是一种解决回归问题的…

【高等数学】3-2多元函数积分学

1. 二重积分 可以想象你有一块不规则的平面薄板,它在一个平面区域上。二重积分就是用来求这个薄板的质量(假设薄板的面密度函数是)。 把区域划分成许多非常小的小方块(类似于把一块地划分成很多小格子),在每个小方块上,密度近似看成是一个常数,然后把每个小方块的质量加…

需求管理流程与工具:国内外10款综合评测

本文中&#xff0c;分享了10款需求管理工具&#xff1a;1.PingCode&#xff1b;2.Worktile&#xff1b;3.纷享销客&#xff1b;4.Teambition&#xff1b;5.Jira&#xff1b;6.Trello&#xff1b;7.Figma&#xff1b;8.万维需求管理&#xff1b;9.ClickUp&#xff1b;10.项目管理…