上期我们完成了游戏大厅的前端部分内容,今天我们实现后端部分内容
1. 维护在线用户
在用户登录成功后,我们可以维护好用户的websocket会话,把用户表示为在线状态,方便获取到用户的websocket会话
java
package org.ting.j20250110_gobang.game;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.HashMap;
import java.util.Map;
@Component
public class OnlineUserManager {
//使用ConcurrentHashMap保证线程安全
private Map<Integer, WebSocketSession> onlineUser = new ConcurrentHashMap<>();
public void enterGameHall(int userId, WebSocketSession session) {
//用户上线
onlineUser.put(userId, session);
}
public void exitGameHall(int userId) {
//用户下线
onlineUser.remove(userId);
}
public WebSocketSession getFromHall(int userId) {
//获取用户的websocket会话
return onlineUser.get(userId);
}
}
这里我们借助一个哈希表就可以实现。
2. 实现webSocket相关方法
上期我们定义了webSocket的处理类,但是并没有完成重写的方法,接下来我们借助维护的在线用户具体实现如下方法

在实现这些方法之前,我们还需要按照上期约定好的信息交互形式定义两个实体类,代表请求和响应:
java
package org.ting.j20250110_gobang.game;
public class MatchRequest {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
java
package org.ting.j20250110_gobang.game;
public class MatchResponse {
private boolean ok;
private String errMsg;
private String message;
public boolean isOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2.1 连接成功
java
//连接成功后执行
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//玩家上线
try {
//获取登录时储存在session中的用户信息,这里WebSocketSession在注册时通过拦截器获取到了session中的内容
User user = (User)session.getAttributes().get("user");
if(onlineUser.getFromHall(user.getId()) == null) {
onlineUser.enterGameHall(user.getId(), session);
System.out.println("用户:" + user.getUsername() + " 已上线");
}else{
//防止重复登录
MatchResponse response = new MatchResponse();
response.setOk(false);
response.setErrMsg("用户已在别处登录");
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
session.close();
}
}catch (NullPointerException e) {
e.printStackTrace();
MatchResponse response = new MatchResponse();
response.setOk(false);
response.setErrMsg("用户未登录");
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
}
}
2.2 连接断开
java
//连接异常时执行
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
//连接异常断开,玩家下线
try {
User user = (User)session.getAttributes().get("user");
//防止重复登录时删除正常登录的在线信息
if(onlineUser.getFromHall(user.getId()).equals(session)) {
onlineUser.exitGameHall(user.getId());
System.out.println("用户:" + user.getUsername() + " 已下线");
}
}catch (NullPointerException e) {
e.printStackTrace();
MatchResponse response = new MatchResponse();
response.setOk(false);
response.setErrMsg("用户未登录");
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
}
}
//连接正常断开后执行
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
//连接正常断开,玩家下线
try {
User user = (User)session.getAttributes().get("user");
//防止重复登录时删除正常登录的在线信息
if(onlineUser.getFromHall(user.getId()).equals(session)) {
onlineUser.exitGameHall(user.getId());
System.out.println("用户:" + user.getUsername() + " 已下线");
}
}catch (NullPointerException e) {
e.printStackTrace();
MatchResponse response = new MatchResponse();
response.setOk(false);
response.setErrMsg("用户未登录");
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
}
}
2.3 处理匹配请求
java
//接收到请求后执行
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
User user = (User) session.getAttributes().get("user");
MatchRequest request = objectMapper.readValue(message.getPayload(), MatchRequest.class);
MatchResponse response = new MatchResponse();
if(request.getMessage().equals("startMatch")) {
//开始匹配,把用户加入匹配队列
//todo
response.setOk(true);
response.setMessage("startMatch");
}else if(request.getMessage().equals("stopMatch")) {
//取消匹配,从匹配队列中移除用户
//todo
response.setOk(true);
response.setMessage("stopMatch");
}else{
response.setOk(false);
response.setErrMsg("非法请求");
}
}
这里=具体的匹配队列功能我们下期再实现