我们的游戏大厅界面主要需要包含两个功能,一是显示用户信息,二是匹配游戏按钮
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");
}
//页面关闭时释放webSocket
window.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 {
//连接成功后执行
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
}
//接收到请求后执行
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
}
//连接异常时执行
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
super.handleTransportError(session, exception);
}
//连接正常断开后执行
@Override
public 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 {
@Autowired
MatchWebSocket matchWebSocket;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(matchWebSocket, "/findMatch") //注意路径和前端对应
//添加拦截器获取到session,方便获取session中的用户信息
.addInterceptors(new HttpSessionHandshakeInterceptor());
}
}