我们的游戏大厅界面主要需要包含两个功能,一是显示用户信息,二是匹配游戏按钮
1. 页面实现
hall.html
<!DOCTYPE html>
<html lang="ch">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>游戏大厅</title><link rel="stylesheet" href="css/common.css"><link rel="stylesheet" href="css/hall.css">
</head>
<body><div class="nav">五子棋</div><div class="container"><div class="dialog"><!-- 展示用户信息 --><div id="screen"></div><!-- 开始匹配 --><button id="match" onclick="findMatch()">开始匹配</button></div></div>
</body>
</html>
hall.css
.container {height: calc(100% - 50px);display: flex;justify-content: center;align-items: center;
}.container .dialog {height: 350px;width: 299px;background-color: white;border-radius: 20px;padding-top: 30px;display: flex;justify-content: center;/* align-items: center; */flex-wrap: wrap
}.dialog *{display: flex;justify-content: center;align-items: center;
}.dialog #screen {width: 250px;height: 150px;background-color: wheat;border-radius: 10px;
}.dialog #match {width: 150px;height: 40px;background-color: rgb(255, 159, 33);border-radius: 10px;
}.dialog #match:active {background-color: rgb(204, 128, 21);
}
2. 获取用户信息接口
当用户进入 游戏大厅时,就应该获取到登录用户的信息显示到页面上,我们使用js代码从访问后端接口获取信息:
<script src="js/jquery.min.js"></script><script>$.ajax({type: 'post',url: '/user/getLoginUser',success: function(result) {if(result.username != null) {let screen = document.querySelector("#screen");screen.innerHTML = '当前玩家:' + result.username + '<br>天梯积分:' + result.score + '<br>比赛场次:' + result.totalCount + '<br>获胜场次:' + result.winCount;}else{alert("获取用户信息失败,请重新登录");location.href = "/login.html";}},error: function() {alert("获取用户信息失败");}});</script>
运行效果:
2. WebSocket前端代码
当用户点击匹配按钮时,需要告知服务器该用户要进行匹配,服务器如果接收到则立即回复表示正在匹配,当匹配成功服务器则又需要发送匹配信息给客户端。这里涉及到服务器主动给客户端发送消息的场景,所以我们使用websocket实现
2.1 初始化websocket
let webSocket = new WebSocket('ws://127.0.0.1:8080/findMatch');webSocket.onopen = function() {console.log("连接成功");}webSocket.onclose = function() {console.log("连接关闭");}webSocket.onerror = function() {console.log("error");}//页面关闭时释放webSocketwindow.onbeforeunload = function() {webSocket.close();}//处理服务器发送的消息webSocket.onmessage = function(e) {}function findMatch() {//检查websocket连接if(webSocket.readyState == webSocket.OPEN) {}else{alert("连接断开,请重新登录");location.href = "/login.html";}}
2.2 实现findMatch()方法
点击开始匹配按钮后就会执行findMatch方法,进入匹配状态,此时我们可以把开始匹配按钮替换成取消匹配按钮,再次点击则会向服务器发送取消匹配请求。
function findMatch() {//检查websocket连接if(webSocket.readyState == webSocket.OPEN) {if($("#match").text() == '开始匹配') {console.log("开始匹配");webSocket.send(JSON.stringify({message: 'startMatch' //约定startMatch表示开始匹配}));}else if($("#match").text() == '匹配中...') {console.log("停止匹配");webSocket.send(JSON.stringify({message: 'stopMatch' //约定stopMatch表示停止匹配}));}}else{alert("连接断开,请重新登录");location.href = "/login.html";}}
2.3 实现onmessage
我们约定服务器返回的响应为包含以下三个字段的json:
- ok: true/false, //表示请求成功还是失败
- errMsg: "错误信息", //请求失败返回错误信息
- message: 'startMatch' / 'stopMatch' / 'success' //success表示请求成功
//处理服务器发送的消息webSocket.onmessage = function(e) {//解析json字符串为js对象let resp = JSON.parse(e.data);if(!resp.ok) {console.log(resp.errMsg);return;}if(resp.message == 'startMatch') {//开始匹配请求发送成功正在匹配//替换按钮描述$("#match").text("匹配中...");}else if(resp.message == 'stopMatch') {//取消匹配请求发送成功已取消匹配//替换按钮描述$("#match").text("开始匹配");}else if(resp.message == 'success'){//匹配成功console.log("匹配成功! 进入游戏房间");locating.href = "/game.html";}else{console.log("非法响应 errMsg:" + resp.errMsg);}}
3. WebSocket后端代码
3.1 注册websocket
创建TextWebSocketHandler子类,重写如下方法:
package org.ting.j20250110_gobang.websocket;import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;@Component
public class MatchWebSocket extends TextWebSocketHandler {//连接成功后执行@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {super.afterConnectionEstablished(session);}//接收到请求后执行@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {super.handleTextMessage(session, message);}//连接异常时执行@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {super.handleTransportError(session, exception);}//连接正常断开后执行@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {super.afterConnectionClosed(session, status);}
}
注册socket:
package org.ting.j20250110_gobang.config;import org.springframework.beans.factory.annotation.Autowired;
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;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import org.ting.j20250110_gobang.websocket.MatchWebSocket;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@AutowiredMatchWebSocket matchWebSocket;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(matchWebSocket, "/findMatch") //注意路径和前端对应//添加拦截器获取到session,方便获取session中的用户信息.addInterceptors(new HttpSessionHandshakeInterceptor());}
}