上期我們完成了游戲大廳的前端部分內容,今天我們實現后端部分內容?
1. 維護在線用戶
在用戶登錄成功后,我們可以維護好用戶的websocket會話,把用戶表示為在線狀態,方便獲取到用戶的websocket會話
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的處理類,但是并沒有完成重寫的方法,接下來我們借助維護的在線用戶具體實現如下方法
在實現這些方法之前,我們還需要按照上期約定好的信息交互形式定義兩個實體類,代表請求和響應:
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;}
}
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 連接成功
//連接成功后執行@Overridepublic 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 連接斷開
//連接異常時執行@Overridepublic 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)));}}//連接正常斷開后執行@Overridepublic 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 處理匹配請求
//接收到請求后執行@Overrideprotected 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")) {//開始匹配,把用戶加入匹配隊列//todoresponse.setOk(true);response.setMessage("startMatch");}else if(request.getMessage().equals("stopMatch")) {//取消匹配,從匹配隊列中移除用戶//todoresponse.setOk(true);response.setMessage("stopMatch");}else{response.setOk(false);response.setErrMsg("非法請求");}}
這里=具體的匹配隊列功能我們下期再實現